
A Practical Guide to Partial Prerendering in Next.js 16
December 4, 2025
Ashish Gogula
When someone opens a webpage, they expect something to appear quickly. Even a small delay can make the experience feel slow. Many pages rely on data that needs time to load, and when that data blocks the entire page, the user is left staring at a blank screen. Developers often work around this by choosing between a static page that loads immediately or a dynamic one that waits for everything.
Next.js 16 introduces Partial Prerendering, a rendering approach that avoids this tradeoff. The idea is simple. The parts of the page that do not depend on fresh data can be generated ahead of time. The rest can be prepared at request time. The user sees the layout and structure of the page right away, and the dynamic content streams in as soon as it is ready. This creates a smoother experience without changing how you think about building pages.
How Partial Prerendering Works
Most pages naturally divide into two types of content. There is a stable shell, which includes layout, headings, and text that rarely changes. This is safe to prerender. Then there is content that depends on live data, such as a user profile, a feed, or a price. This part needs to be generated at request time.
Partial Prerendering lets Next.js treat these two categories differently. The stable structure can be generated in advance. The dynamic sections can wait for their data. React Suspense marks the boundary between the two. When the server encounters a Suspense boundary, it knows that everything outside can be delivered immediately. Everything inside can load later without blocking the rest of the page.
When the request arrives, the static shell is sent to the browser right away. The dynamic region is not ready, so the user sees a placeholder. This placeholder is intentional. It signals progress without delaying the visual structure of the page. When the server finishes preparing the dynamic region, the browser receives a small HTML update that replaces the placeholder with real content. There is no interruption. The page stays visible the entire time.
Why Suspense Matters
Suspense is the key mechanism behind PPR. It defines where the static part ends and the dynamic part begins. In typical client-side usage, Suspense is often associated with showing a loading indicator. In server rendering, it takes on a more important role. Suspense allows the server to pause part of the rendering work without delaying the rest of the page.
Anything outside the boundary is treated as static. Anything inside the boundary is evaluated when the data is ready. This makes the rendering pipeline predictable. Developers do not need special configuration. They simply wrap the dynamic part in Suspense and keep the layout static. Next.js recognizes the structure and handles the prerendering and streaming steps on its own.
How This Feels to the User
From the user's perspective, a page that uses Partial Prerendering feels noticeably faster. They click a link and immediately see the layout, the heading, and the general shape of the content. This creates a sense of stability. Even if the data takes several seconds to load, the user is not waiting in the dark.
The placeholder in the dynamic section gives a clear signal that content is on the way. The moment the server completes the slow work, the actual data replaces the placeholder. The transition is smooth and requires no further loading on the user's side. Although the total server time might remain the same, the perceived speed improves significantly.
Enabling the Feature
Before using Partial Prerendering, you need to enable the new Cache Components architecture in your configuration. In Next.js 16, this single flag unlocks both PPR and the new caching directives.
Add this to your next.config.ts:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
cacheComponents: true, // Enables Partial Prerendering & Cache Components
};
export default nextConfig;How This Looks in Practice
A small demonstration project helps illustrate how Partial Prerendering behaves in a real environment. The example keeps the structure minimal so that the rendering flow is easy to understand. A slow API route introduces a brief delay before returning data. An async Server Component consumes that data and is placed inside a Suspense boundary, while the rest of the layout remains fully static.
import { Suspense } from 'react';
import SlowData from '@/components/SlowData';
import Skeleton from '@/components/Skeleton';
export default function PPRPage() {
return (
<div>
<h1>Partial Prerendering Demo</h1>
<p>This header loads instantly as part of the static shell</p>
{/* Suspense boundary separates static from dynamic */}
<Suspense fallback={<Skeleton />}>
<SlowData />
</Suspense>
</div>
);
}When the page loads, the prerendered shell is available immediately. The header and descriptive text appear without waiting for any backend work, since they do not rely on request-time data. The dynamic section enters a pending state, and a lightweight skeleton placeholder occupies the space where the final content will appear. Once the server resolves the dynamic work, the browser receives a streamed update and the placeholder is replaced with the completed component. The visual transition is smooth and does not block the rest of the page.
This pattern reflects how Partial Prerendering is designed to operate. Static elements are always ready at the initial render, while dynamic regions resolve independently inside Suspense. The example offers a clear reference for how Next.js 16 separates static and dynamic work and how streaming updates arrive in production environments.
The full source code is available on GitHub, and a live deployment is hosted on Vercel:
GitHub: https://github.com/ashishgogula/nextjs-16-ppr-demo
Live Demo: https://nextjs-16-ppr-demo.vercel.app
Looking Ahead
Partial Prerendering arrives at a moment when the web is becoming more dynamic and more personalized. At the same time, expectations around performance are higher than ever. PPR provides a practical way to meet both needs. It keeps pages responsive while still allowing fresh data to flow in when available.
As applications grow, these patterns will become even more useful. A dashboard can reveal its structure before all metrics are ready. A content-heavy page can show its layout early while related data loads in the background. An AI feature can start the interaction immediately and reveal the result when the server finishes its work.
The idea behind PPR is simple, and that simplicity is what makes it powerful. Developers structure their pages naturally, and the framework determines the most efficient way to deliver them. It is a step toward a future where the distinction between static and dynamic rendering matters less, and the focus shifts to providing a consistent, fast experience.