PPR, SSR, SSG, and ISR are the four rendering strategies you meet in Next.js documentation and job postings. In the App Router they have newer names: server-side rendering is dynamic rendering, static site generation is static rendering, and incremental static regeneration is revalidation. Partial Prerendering changed the most, because it is no longer a per-route opt-in.
These are not four buttons you pick between. Next.js chooses the strategy for each part of a route based on the APIs you use.
This article assumes Cache Components, enabled with cacheComponents: true in next.config.ts. That flag is opt-in, and turning it on makes Partial Prerendering the default rendering model for every route.
The four strategies at a glance
The difference that matters is when the HTML is produced and how fresh the data can be.
| Strategy | Rendered | Fresh data | Served from |
|---|---|---|---|
| SSR | Per request | Yes | The server |
| SSG | At build time | Only after redeploy | CDN |
| ISR | At build time, then revalidated | After the revalidate window | CDN, with background refresh |
| PPR | Static shell at build time, rest at request | Per boundary | CDN shell, then streamed |
SSR is the slowest per request but always fresh. SSG is the fastest and cheapest but frozen until the next deploy. ISR and PPR combine the two, which is why modern Next.js leans on them.
What each term means in the App Router
Server-side rendering used to be a mode you enabled for a whole page. In the App Router the equivalent is dynamic rendering, and it happens when a component reads a request-time API or uncached data.
// app/time/page.tsx
import { connection } from 'next/server'
import { Suspense } from 'react'
async function Clock() {
await connection()
return <p>{new Date().toISOString()}</p>
}
export default function TimePage() {
return (
<Suspense fallback={<p>Loading time...</p>}>
<Clock />
</Suspense>
)
}connection() tells Next.js to wait for a real request before continuing, so the timestamp is never baked into the shell. The browser gets the fallback first and the timestamp streams in. There is no ssr: true flag to set, the use of request-time data makes the decision, and the Suspense boundary is what keeps the rest of the route prerenderable.
Static site generation is the same idea from the other side. A page that uses only build-time data prerenders to HTML and never runs again until the next deploy.
ISR and PPR close the gap
ISR keeps the speed of static HTML while allowing updates. A page is prerendered, then rebuilt in the background when its revalidation window passes or when you invalidate it on demand. For the full walkthrough, see Incremental Static Regeneration.
PPR goes further and splits a single route. The static shell ships instantly from a CDN, and the dynamic parts stream in when ready.
You do not enable PPR in Next.js 16, it is the default under Cache Components. For the pipeline, see how Partial Prerendering works.
Which one should you use
Choose by how often the content changes and whether it depends on the visitor.
- Static content that rarely changes: static rendering.
- Content that changes a few times a day: ISR or a cached function.
- Per-visitor or per-request content: dynamic rendering inside a Suspense boundary.
- A page that mixes all three: PPR, which you get by default.
The common mistake is thinking you must lock a page to one strategy. In Next.js 16 the honest answer is usually a mix, and the framework builds that mix for you.
Rune AI
Key Insights
- SSR maps to dynamic rendering in the App Router.
- SSG maps to static rendering at build time.
- ISR is revalidation, rebuilding static pages in the background.
- PPR mixes a static shell with streamed dynamic content and is the default once Cache Components is enabled.
- The strategy is chosen by the APIs you use, not by one config flag.
Frequently Asked Questions
Is SSR still a thing in the App Router?
Does PPR replace ISR?
Conclusion
PPR, SSR, SSG, and ISR are not four competing buttons. In the App Router they are the same rendering system seen from different angles, and Next.js 16 picks the right mix for each route automatically.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.