Partial Prerendering (PPR)

Static shells with dynamic holes.

Next.js4 min readConcept 65 of 66

The Best of Both Worlds

For years, developers had to choose between Static Site Generation (fast, but generic) and Server-Side Rendering (personalized, but slower).

**Partial Prerendering (PPR)** merges them. During the build step, Next.js generates a static HTML shell of your page. However, it leaves 'holes' wherever it finds a <Suspense> boundary wrapping dynamic data.

Fixing the All-or-Nothing Trap

Before PPR, if a static e-commerce homepage wanted to display the user's name in the header (which requires reading a cookie), the *entire page* was forced to become dynamic, severely harming TTFB.

With PPR, the user receives the static homepage layout instantly from the Edge CDN. A few milliseconds later, the personalized header streams into the <Suspense> hole.

Implementation

To use it in Next.js 15, enable it in config and explicitly opt-in at the route level:

typescript

// app/page.tsx

import { Suspense } from 'react';

import { CartCount, Skeleton } from '@/components';

// Opt into PPR

export const experimental_ppr = true;

export default function Page() {

return (

<main>

<StaticHero />

<Suspense fallback={<Skeleton />}>

{/* This streams in dynamically! */}

<CartCount />

</Suspense>

</main>

);

}

PPR Streaming Visualization

Watch how a static shell is served instantly from the edge, followed by a dynamic payload streaming into the Suspense boundary.

Origin DB
Edge CDN
Static Shell
Stream Chunk
TTFB
0ms
store.com/checkout
3
Static HTML Shell

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1How does Partial Prerendering (PPR) handle a page that contains both static content and a dynamic cookie read?

Remember this

  • PPR combines SSG (static shell) and SSR (dynamic streaming) on the same page.
  • It solves the 'all-or-nothing' rendering dilemma.
  • You must wrap dynamic Server Components in <Suspense> to create the 'holes' for the static shell.
  • Dynamic functions called outside of Suspense will break the static shell.

Done with this concept?

Mark it complete to track your progress. No login needed.