Skip to content

· nextjs · github

Static Next.js on GitHub Pages

GitHub Pages is a folder of files. Next.js is happy to write that folder if you ask it the long way.

const basePath = process.env.GITHUB_PAGES === "true" ? "/mira" : ""

const nextConfig = {
  output: "export",
  trailingSlash: true,
  basePath,
  images: { unoptimized: true },
}

output: "export" writes out/. trailingSlash turns /blog/the-lab-is-open into a folder with index.html, which is how Pages resolves a directory. basePath is /mira in production because this repo is a project site. Local next dev has no prefix, so the same code runs at /.

images.unoptimized is not optional. Pages has no image optimizer. A raw <img src="/mira.jpg"> also needs the prefix. next/link adds it. An <a> does not.

The underscore trap

Next.js puts assets in _next/. Jekyll, which GitHub still runs on a user site, ignores names that start with _ unless you list them.

This repo deploys with actions/deploy-pages and a .nojekyll file, so Jekyll stays out of the way. If you copy out/ into a Jekyll site (the landing page at TheWhiteWitchTM.github.io does this for /mira/), that parent _config.yml must include: [_next]. The post-build script in this repo updates that list from the files it just wrote.

A 404 that is really a slash

/tools/unfurl without the trailing slash is a file GitHub does not have. /tools/unfurl/ is unfurl/index.html. The config above makes every internal link end in a slash. If a 404 comes back, look there first, then look at basePath.

The build

npm run build

That is GITHUB_PAGES=true, an RSS pass, next build, then scripts/gh-pages.mjs. The script writes .nojekyll, copies out/ next to the landing page when that folder exists, and refreshes the Jekyll include list so _next actually ships.