Static Generation at Request Time in Next.js
4 min read Augustyn Głowacki
The common way to implement SSG in Next.js is to generate every page up front, during the build. Generating a page the first time someone actually requests it is another option: nothing pre-builds, and Next.js caches each page after its first visit, the same as any other static route. I used this to remove RudderStack's 3,500-page integration catalog from its build at Bejamas, cutting a 40-minute deploy to about 3 minutes.
How does Next.js decide when a static page gets built?
The common way to implement SSG is to generate every page up front, during the build (Next.js docs, all paths at runtime). That works well until the page count gets large enough that the waiting time for the build itself becomes the cost.
What happens if generateStaticParams returns an empty array?
Every path gets generated the first time someone requests it, and nothing is prerendered during the build. Next.js’ own wording for the App Router: “To statically render all paths the first time they’re visited, return an empty array (no paths will be rendered at build time)” (Next.js docs, all paths at runtime). It is a two-line change in the route:
// app/integrations/[slug]/page.js
export async function generateStaticParams() {
return [];
}
The empty array is load-bearing. Returning nothing at all, or deleting the function, is a different behaviour: the docs are explicit that “you must always return an array from generateStaticParams, even if it’s empty. Otherwise, the route will be dynamically rendered” - dynamic meaning re-rendered per request rather than cached after the first one.
What has to be true for this to work?
Four conditions, and all four are worth checking before moving a large route.
- Router and version. This is App Router behaviour, as documented on the
generateStaticParamsreference page for Next.js 16 (page last updated 25 August 2026). The Pages Router has its own API for on-demand generation,getStaticPathswith afallbackoption, and its semantics are not the same - do not port the reasoning across. - Un-generated paths are allowed through. The
dynamicParamssegment config decides what happens when a visitor hits a dynamic segment thatgenerateStaticParamsdid not return, and it defaults totrue(Next.js route segment config). Set it tofalseand those paths 404, at which point an empty array means the route serves nothing at all. Note also that Next.js 16 removes this option, and the rest of the segment config, when Cache Components is enabled. - You have a way to invalidate a page. Nothing rebuilds on its own. A CMS webhook calling
revalidatePathfor the changed page is what turns “cached forever” into “current” - without it, the first render is the last one until the next deploy. - Your host actually keeps the cache. Next.js hands the cached output to the deployment platform, so how long a generated page survives, and whether it survives a deploy at all, is the host’s behaviour rather than the framework’s. Read your host’s docs on that before assuming a page renders once.
What’s the tradeoff of generating pages on demand?
The cost moves from the build to the first request for each page.
- Pro: editors publish in the CMS and see it live in seconds - no need to wait for the build to complete.
- Con: the first visitor to a page that has not been generated yet waits for it to render. On a catalog where most pages get little traffic, that means the slow request is a common request, not a rare one, and it lands on real visitors rather than on CI.
- Con: hosting costs get less predictable, since you’re paying for cache reads and writes instead of a fixed build.
Which approach fits depends on the case - how many pages, how often the content changes, how much traffic the long tail gets, and what a slow build actually costs.
What did this change for a real deploy?
At Bejamas, I worked on RudderStack’s marketing site, with an integration catalog of 3,500+ pages - one page per platform pairing, the kind of programmatically generated content every dev tool site accumulates. Every deploy rebuilt all 3,500+ of them, and the whole thing was taking about 40 minutes. Moving those pages to request-time generation took them out of the build entirely, and the deploy dropped to about 3 minutes.
