@rsalianto/git-heatmap-next
v0.1.7
Published
Next.js App Router route handlers for GitHub/GitLab contribution data — token stays on the server
Downloads
1,172
Maintainers
Readme
@rsalianto/git-heatmap-next
Next.js App Router route handler factories for serving GitHub and GitLab contribution data — your token stays on the server, the browser only receives HeatmapData JSON.

Part of the
@rsalianto/git-heatmapfamily — available for React, Vue, Angular, Vanilla JS, and Next.js.
Installation
npm install @rsalianto/git-heatmap-nextQuick start
1. Add your token to .env.local
GITHUB_TOKEN=ghp_your_token_hereGenerate one at github.com/settings/tokens with the
read:userscope.
2. Create the API route
// app/api/contributions/route.ts
import { createGitHubHandler } from "@rsalianto/git-heatmap-next";
export const GET = createGitHubHandler({ username: "your-github-username" });3. Use it in your component
import { GitHeatmap } from "@rsalianto/git-heatmap-react";
export default function Page() {
return <GitHeatmap apiUrl="/api/contributions" />;
}GitHub handler
// app/api/contributions/github/route.ts
import { createGitHubHandler } from "@rsalianto/git-heatmap-next";
export const GET = createGitHubHandler({
username: "your-github-username",
// token falls back to process.env.GITHUB_TOKEN automatically
revalidate: 3600, // cache for 1 hour (default)
});Options
| Option | Type | Default | Description |
|---|---|---|---|
| username | string | — | GitHub username (required) |
| token | string | GITHUB_TOKEN env var | GitHub personal access token (read:user scope) |
| revalidate | number | 3600 | Cache-Control s-maxage in seconds |
| levels | LevelConfig[] | DEFAULT_LEVELS | Custom contribution level thresholds |
GitLab handler
// app/api/contributions/gitlab/route.ts
import { createGitLabHandler } from "@rsalianto/git-heatmap-next";
export const GET = createGitLabHandler({
username: "your-gitlab-username",
// token: falls back to process.env.GITLAB_TOKEN (optional for public profiles)
// baseUrl: "https://gitlab.your-company.com" ← for self-hosted instances
revalidate: 3600,
});Options
| Option | Type | Default | Description |
|---|---|---|---|
| username | string | — | GitLab username (required) |
| token | string | GITLAB_TOKEN env var | GitLab personal access token (optional for public profiles) |
| baseUrl | string | https://gitlab.com | GitLab instance URL |
| revalidate | number | 3600 | Cache-Control s-maxage in seconds |
| levels | LevelConfig[] | DEFAULT_LEVELS | Custom contribution level thresholds |
Response format
Both handlers return HeatmapData JSON. This is also the format expected by the apiUrl prop in all component packages:
{
"totalContributions": 312,
"source": "github",
"weeks": [
{
"days": [
{ "date": "2025-01-05", "count": 0, "level": 0 },
{ "date": "2025-01-06", "count": 3, "level": 1 },
{ "date": "2025-01-07", "count": 8, "level": 2 },
{ "date": "2025-01-08", "count": 14, "level": 3 },
{ "date": "2025-01-09", "count": 22, "level": 4 },
{ "date": "2025-01-10", "count": 1, "level": 1 },
{ "date": "2025-01-11", "count": 0, "level": 0 }
]
}
]
}On error the handler responds with { "error": "<message>" } and HTTP status 500.
Custom backend
If you use another host (Gitea, Forgejo, Bitbucket, etc.) skip this package and call the core fetcher/normalizer directly:
// app/api/contributions/route.ts
import { normalizeManual } from "@rsalianto/git-heatmap-core";
import { NextResponse } from "next/server";
export async function GET() {
const raw = await myCustomBackend.getContributions();
const data = normalizeManual(raw.map(r => ({ date: r.day, count: r.commits })));
return NextResponse.json(data, {
headers: { "Cache-Control": "s-maxage=3600, stale-while-revalidate" },
});
}Related packages
@rsalianto/git-heatmap-react— React component@rsalianto/git-heatmap-vue— Vue 3 component@rsalianto/git-heatmap-core— Core utilities and fetchers
