Next.js App Router: Partial Prerendering and Streaming Explained
Next.js 15+ combines static shells with dynamic islands through Partial Prerendering (PPR). Learn how PPR, streaming, and the App Router change how you architect fast, personalized pages.
Static vs. Dynamic Was a False Dichotomy
For years, pages were either fully static (fast, cacheable, stale) or fully dynamic (personalized, slow, uncacheable). Next.js App Router introduced a hybrid: prerender a static HTML shell at build time, then stream dynamic holes filled at request time. Partial Prerendering (PPR) formalizes this pattern so marketing headers and footers ship instantly while user-specific content streams in milliseconds later.
How PPR Works Under the Hood
At build time, Next.js identifies static segments and dynamic Suspense boundaries. The static shell is served from the CDN edge; dynamic segments execute on the server per request and stream into placeholder slots. The result feels instant: users see layout and navigation immediately while personalized widgets populate.
// app/dashboard/page.tsx
export const experimental_ppr = true;
export default function DashboardPage() {
return (
<main>
<StaticNav /> {/* prerendered shell */}
<Suspense fallback={<StatsSkeleton />}>
<UserStats /> {/* streamed per request */}
</Suspense>
</main>
);
}
Streaming and Suspense Boundaries
Every async Server Component inside Suspense becomes a streaming unit. Place boundaries around slow data sources, such as recommendations, notifications, or A/B test variants, so fast content is not blocked by slow queries. Fallback UI should match final layout dimensions to avoid Cumulative Layout Shift (CLS).
Caching Semantics in App Router
Understand fetch caching, revalidate tags, and route segment config (dynamic, revalidate). PPR works best when static portions use aggressive caching and dynamic portions call cookies(), headers(), or uncached fetches explicitly.
Migration Mindset
- Audit pages for truly dynamic vs. deferrable content.
- Split client interactivity into small islands with
"use client". - Measure TTFB, LCP, and INP before and after. PPR helps perceived speed even when total bytes are similar.
Partial Prerendering is how Next.js delivers both edge speed and server personalization without maintaining separate static and SSR code paths. Design with streaming first, and your App Router pages will scale from brochure sites to authenticated dashboards.