Skip to content

Repository files navigation

Next.js 16 – Partial Prerendering (PPR) Demo

License Next.js PPR

"The holy grail of web performance: Instant static shell + Streaming dynamic content."

PPR Demo Preview (A minimal reproduction of Next.js 16 Partial Prerendering behavior)

This project is a minimal, production-ready demonstration of Partial Prerendering (PPR) in Next.js 16, designed to showcase the new Cache Components architecture without the complexity of a full app.

It visually demonstrates the difference between:

  • Static Shell Rendering: Layouts and headers load instantly (Build Time).
  • Dynamic Streaming: Critical data streams in parallel (Request Time).

🚀 Quick Start

1. Clone & Install

git clone [https://github.com/ashishgogula/nextjs-16-ppr-demo.git](https://github.com/ashishgogula/nextjs-16-ppr-demo.git)
cd nextjs-16-ppr-demo
npm install

2. Run Production Build (Required for PPR)

Note: PPR behavior is best observed in a production build, as next dev does not fully emulate static shell serving.

npm run build
npm start

3. Verify

Visit http://localhost:3000/ppr to see the instant shell + streaming data in action.


🛠 Technical Architecture

This demo uses the new Cache Components architecture in Next.js 16, which unifies Partial Prerendering and Caching into a single configuration.

The Config (next.config.ts)

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  cacheComponents: true, // Unlocks PPR and 'use cache'
};

export default nextConfig;

Route Structure

  • /ppr: The main demo route.
    • Static Shell: layout.tsx + <h1> headers (Prerendered).
    • Dynamic Hole: <SlowData /> component wrapped in <Suspense>.
  • /api/slow: A simulated delay endpoint (5s) to guarantee predictable "slow" data for testing.

📂 Project Structure

app/
  api/
    slow/
      route.ts        # Dynamic API route with intentional 5s delay
  ppr/
    page.tsx          # The PPR Route (Static Shell + Dynamic Hole)
    layout.tsx        # Static layout (Critical for shell rendering)
components/
  SlowData.tsx        # Async Server Component (Fetches data)
  Skeleton.tsx        # Fallback UI (displayed instantly)
lib/
  slowFetch.ts        # Helper to fetch with { cache: 'no-store' }

⚠️ Design Choices (Pitfalls Avoided)

To ensure PPR is actually enabled, this demo avoids common de-optimizations that force full dynamic rendering:

  • No Async Layouts: layout.tsx is kept synchronous to allow the shell to generate at build time.
  • No Cookie/Header Access in Layouts: We strictly avoid request-time data in the static root.
  • Granular Caching: We use cache: 'no-store' inside the component (SlowData), rather than forcing the entire route to be dynamic.
  • Suspense Boundaries: Dynamic regions are strictly isolated inside <Suspense> to unblock the rest of the UI.

☁️ Deploying to Vercel

  1. Fork this repository.
  2. Import it to Vercel.
  3. Deploy (Next.js 16 preset is automatic).

Once deployed, the static shell will be served from the Edge, while the dynamic content streams from a Server Function.


📝 License

This project is open source and available under the MIT License.


Built by Ashish Gogula

About

Next.js 16 Partial Prerendering Demo

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages