« All posts

Partial Prerendering in Next.js: Static Shell, Dynamic Stream

Next.js's experimental PPR feature serves a static HTML shell instantly from the CDN while streaming dynamic Suspense sections from origin in the same response, replacing ISR tradeoffs.

Next.js's Partial Prerendering (PPR) splits a page into two rendering phases within a single HTTP response: at build time, everything that doesn't read dynamic request data is frozen into a static HTML shell served from the CDN edge, while at request time, Suspense-wrapped dynamic sections stream from the origin into that same response. Users see navigation, titles, and descriptions at CDN speed, with dynamic pieces like stock status or personalized recommendations arriving moments later.

This approach eliminates ISR's whole-page staleness window and full dynamic rendering's origin latency penalty of waiting for the slowest query. Enabling it requires no changes to existing Server Component or Suspense patterns — just an experimental.ppr: 'incremental' config flag plus a per-route experimental_ppr = true export. Components outside Suspense boundaries cannot call cookies(), headers(), or searchParams, or the build fails with an explicit error.

PPR composes cleanly with use cache: PPR governs the CDN boundary while use cache memoizes origin renders inside Suspense. It suits pages that are mostly static with isolated dynamic islands — product pages with live inventory, or SaaS dashboards with cached sidebars and real-time metrics. Though still experimental in Next.js 15 and 16, it's reportedly used internally by Vercel in production, though its API may shift before reaching stable.