Blog
next.jsisrgithub

Live project cards without a database

The project cards show a live language dot, star count and last-push time straight from GitHub. There is no database and no backend service — just a static site with an hourly refresh.

Raw repo lists look bad

Fetching a user's repositories and rendering them directly gives you ugly names, coursework, forks and no thumbnails. So the display source of truth is a curated overlay in the repo:

type Project = {
  slug: string;
  repo: string | null;   // "owner/name" — keyed for the sync
  name: string;          // the overlay wins for everything shown
  tagline: string;
  tech: string[];
};

The overlay owns the name, tagline, tech list and ordering. GitHub only supplies the numbers.

The sync

For each project with a repo, one request to the GitHub API, cached with Next's ISR:

const res = await fetch(`https://api.github.com/repos/${repo}`, {
  headers,
  next: { revalidate: 3600, tags: ["github"] },
});

A GITHUB_TOKEN lifts the anonymous rate limit; without it the sync still works. A push webhook can hit /api/revalidate to bust the github tag sooner than the hourly window.

The part that matters: graceful failure

fetchRepoStats never throws. Any non-200 response, any network error, returns null:

try {
  const res = await fetch(url, { headers, next: { revalidate: 3600 } });
  if (!res.ok) return null;
  // ...parse and return stats
} catch {
  return null;
}

When it returns null, the card simply renders without its stats rail. The page is built from the overlay regardless of whether GitHub is reachable. I tested it with a deliberately invalid token: the site renders in full, the rail is just absent. GitHub being down is not the site's problem.