Next.js - Partial Pre-Rendering



Partial Pre-rendering (PPR) is a rendering pattern in Next.js that combines static and dynamic content in a single page. The static contents along with static fallback for dynamic contents will be pre-rendered at the build time. The dynamic contents will be rendered as per request from user. This method ensures a faster initial page loads as the static content is pre-rendered, and results in better SEO and user experience.

Note: Partial Prerendering is an experimental feature only available on canary browser and is subject to change. It is not ready for production use.

How Partial Pre-Rendering Works?

Partial Pre-rendering works by combining static content with dynamic content. Here's how it works:

Initial Static Content

  • At build time, Next.js generates a static shell of the page
  • This includes all the static content that doesn't need real-time data
  • When a user visits the page, they see the static shell immediately without any loading.

Dynamic Content Streaming

  • Dynamic parts of the page are loaded on client-side.
  • These parts are wrapped in React Suspense boundaries, and while loading, they will show fallback content.
  • Once the dynamic content is loaded, it will replace the fallback content.

Example of Partial Pre-Rendering

In the following example, we have a page that displays static content and dynamic content. The static content is pre-rendered at build time, and the dynamic content is loaded on the client-side. The dynamic content is . In short,

  • The 'StaticContent' component is pre-rendered and served immediately
  • The 'DynamicProducts' component fetches products from an API
  • The 'Page' component wraps the dynamic component in a React Suspense component that shows a loading state while the content is being fetched.
// app/page.tsx

import { Suspense } from 'react'

// Static, pre-rendered content
function StaticContent() {
  return (
    <div>
      <h1>Welcome to Our Store</h1>
      <p>Browse our latest collection of products</p>
    </div>
  )
}

// Dynamic, streaming content
async function DynamicProducts() {
  // Simulate fetching products from an API
  const products = await fetch('https://jsonplaceholder.typicode.com/users', {
    // This cache option enables PPR
    cache: 'no-store'
  }).then(res => res.json())

  return (
    <div>
      {products.map(product => (
        <div key={product.id}>
          <h2>{product.name}</h2>
          <p>{product.price}</p>
        </div>
      ))}
    </div>
  )
}

export default function Page() {
  return (
    <main className="p-8">
      {/* Static content is pre-rendered */}
      <StaticContent />
      
      {/* Dynamic content is loaded client-side with loading state */}
      <Suspense fallback={<div>Loading products...</div>}>
        <DynamicProducts />
      </Suspense>
    </main>
  )
}

Output

In the output below, a loading component is visible before the dynamic content is being fetched. Once the content is loaded, it is replacing the loading component.

Next.js Partial Pre-rendering
Advertisements