-1

I'm experimenting with Next.js 16's new Cache Components and Partial Prerendering (PPR) to build a product page that:

  • Serves a static shell instantly (HTML for layout, header, footer)
  • Streams the dynamic product data inside <Suspense>

I expected the first request to generate the static shell + stream dynamic content, and subsequent requests to serve the full HTML from cache (if data hasn't changed).

But here's what's happening:

Code

// app/products/[id]/page.tsx
import { getProduct } from '@/lib/products';
import { Suspense } from 'react';

export const revalidate = 3600; // 1 hour

export default async function ProductPage({ params }: { params: { id: string } }) {
  return (
    <div>
      <header>Header — Static</header>
      <Suspense fallback={<p>Loading product...</p>}>
        <ProductData id={params.id} />
      </Suspense>
      <footer>Footer — Static</footer>
    </div>
  );
}

async function ProductData({ id }: { id: string }) {
  'use cache'; // Enable Cache Components
  const product = await getProduct(id); // Should be cached
  return (
    <section>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </section>
  );
}

    // lib/products.ts
import { cache } from 'react';

export const getProduct = cache(async (id: string) => {
  console.log('Fetching product:', id);
  // Simulate API delay
  await new Promise(r => setTimeout(r, 2000));
  return {
    id,
    name: `Product ${id}`,
    description: 'Lorem ipsum...',
  };
});

Actual Behavior

First request: Works perfectly — shell loads instantly, product streams after 2s

Second request (within 1 hour):

  • Shell loads instantly (good)
  • But "Loading product..." fallback flashes for ~100ms, then product appears
  • Console: Fetching product:123 logs again

Why is the dynamic segment not cached and served instantly on subsequent requests?

What I’ve Tried

  • cacheLife('1h') on the function → no effect

  • export const dynamic = 'force-dynamic' removed

  • Verified next.config.ts has:

    experimental: { ppr: true, cacheComponents: true }

  • Using next start (production mode)

  • No cookies(), headers(), or auth in the chain

Questions

  1. Does PPR + Cache Components only cache the static shell, not the dynamic content?
  2. How can I make the entire page (shell + dynamic data) cacheable and instant on repeat visits?
  3. Is there a way to pre-warm the dynamic segment into the PPR cache?

Versions

Next.js: 16.0.0 React: 19.0.0 Node: 20.x

Any insight into how PPR and Cache Components interact would be amazing!

1
  • 1
    I believe you want to use cacheLife inside <ProductData /> instead of revalidate As far as I knowrevalidate is for the whole path so you could be revalidating the path and setting the cache component's return to stale so it refetches, showing you the loading indicator. Try cacheLife directly under "use cache"! Commented Nov 13 at 18:40

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.