Keeping every page static in Next.js 16
· 1 min read
This site has three languages and not one page is rendered on request. Here is the setup, and the two mistakes that quietly turn a static page into a dynamic one.

Tell the framework every param up front
A dynamic segment such as [locale] or [slug] is static only when the build knows all of its values.
// app/[locale]/blog/[slug]/page.tsx
export const dynamicParams = false
export function generateStaticParams() {
return locales.flatMap((locale) => getPosts(locale).map(({ slug }) => ({ locale, slug })))
}dynamicParams = false matters: without it, an unknown slug is rendered on demand instead of returning a 404.
Do not read the request
Reading cookies(), headers() or searchParams in a server component opts the whole route out of static
generation. The usual offender in a multilingual site is locale detection.
| Approach | Result |
|---|---|
Redirect by Accept-Language in a proxy | A function runs on every request |
| Locale in the URL only | Fully static |
English without a prefix, still static
The default language has no /en prefix. Instead of a proxy function, a rewrite in next.config.ts maps the
unprefixed path onto the [locale] segment. Rewrites are resolved by the CDN router.
async rewrites() {
return {
afterFiles: [
{ source: '/', destination: '/en' },
{ source: '/:path((?!en|pt-br|es|admin|api|_next).*)', destination: '/en/:path' },
],
}
}Check the build output
The build prints a table. Every public route should show ● (SSG) or ○ (static), never ƒ.
├ ● /[locale]/blog/[slug]
│ ├ /en/blog/hello-world
│ └ /pt-br/blog/hello-worldIf a route shows ƒ, something in its tree read the request.