
Every Next.js project eventually hits the same fork in the road: should this page be built once and served from a cache, or rendered fresh on every request? Get it wrong and a marketing page ships with stale content, or a personalized dashboard pays a rendering tax it never needed to pay. Get it right, page by page, and the same app can serve both a blazing-fast blog and a real-time account page without either one compromising the other.
Static Site Generation: Build Once, Serve Forever
With Static Site Generation (SSG), Next.js renders a page’s HTML at build time. The result is cached and served identically to every visitor until the next build or revalidation. In the App Router, this is the default behavior for any route that doesn’t read request-time data — no special configuration required.
- Fastest possible delivery. A statically generated page is just a file sitting on a CDN edge node. There’s no server computation between the request and the response.
- Cheapest to run at scale. Ten visitors or ten million, the server does the same amount of work: none, per request.
- The trade-off: without revalidation, content can go stale between builds. Next.js solves this with Incremental Static Regeneration (ISR), which lets a static page revalidate in the background on a schedule or on demand, without a full site rebuild.
SSG is the right default for content that’s the same for every visitor: marketing pages, blog posts, documentation, product listings that don’t need live inventory counts.
Server-Side Rendering: Fresh HTML on Every Request
Server-Side Rendering (SSR) generates the HTML on the server at request time, using whatever data is current at that exact moment. In the App Router, a route becomes dynamic — and therefore server-rendered per request — the moment it reads something request-specific: cookies, headers, search params, or an uncached data fetch.
- Always current. Every response reflects the latest data, which matters for account dashboards, live pricing, or personalized content.
- Higher server cost. Every request triggers real computation on the server, which means slower Time to First Byte compared to a cached static page, and infrastructure costs that scale with traffic.
- Necessary, not optional, for certain data. If a page depends on the logged-in user’s identity or on data that changes every few seconds, there’s no static alternative that’s actually correct.
The Real Question Isn’t “Which One” — It’s “Which Parts”
The App Router made rendering strategy a per-route, sometimes per-component decision rather than a whole-app setting. A single e-commerce product page can have a statically generated layout and description, while the “3 people are viewing this right now” widget and the live stock count render dynamically. That granularity is the entire point of the shift away from the old Pages Router model, where a page was either getStaticProps or getServerSideProps and nothing in between.
A Practical Decision Framework
- Choose SSG when: the content is the same for every visitor, changes infrequently, and speed matters most — blogs, marketing sites, documentation.
- Add ISR when: you want SSG’s speed but the content updates periodically — product catalogs, news listings, pricing pages.
- Choose SSR when: the response genuinely depends on the specific request — authenticated dashboards, search results, anything reading cookies or headers.
- Mix both when: a single page has a stable shell and a small dynamic slice — this is exactly the case Partial Prerendering was built to handle, and it’s worth understanding once you’ve got SSG and SSR straight.
The Bottom Line
SSG and SSR aren’t competing philosophies to pick once for an entire project — they’re two tools for two different jobs, and the App Router is built to let you use both in the same app, sometimes on the same page. Start every route by asking whether it needs request-time data. If it doesn’t, default to static and let ISR handle freshness. If it does, render it dynamically and don’t fight the framework for speed you can’t actually get.