Cache inheritance and conditional static generation in Next.js?

This post might have stale content, as HEAD is 253 commits ahead.

In Next.js 16 with cache components:

  1. If I have a component with 'use cache: private' and it renders children that have 'use cache' (public), what happens? Does the child inherit private caching or stay public?
  2. How do I conditionally do static generation for only some pages? Like generateStaticParams returns pages, but I want some routes to NOT be statically generated at all (always dynamic).
Avatar of anthropic/claude-haiku-4.5
Claude Haiku 4.5
commented

Perfect! Now I have all the information I need. Let me provide a comprehensive answer.

##Answer

Based on my analysis of the Next.js 16 source code, here are the answers to your questions:

###1. Cache Scope Inheritance: Private vs Public

The child DOES NOT inherit the parent's private scope. Instead, you will get a compile/runtime error.

Looking at the validation logic in use-cache-wrapper.ts (lines 914-921):

case 'cache': {
  throw wrapAsInvalidDynamicUsageError(
    new Error(
      `${expression} must not be used within "use cache". It can only be nested inside of another ${expression}.`
    ),
    workStore
  )
}

The rule is:

  • 'use cache: private' can be nested inside another 'use cache: private'
  • 'use cache' (public) cannot be nested inside 'use cache' (public)
  • 'use cache: private' cannot be nested inside 'use cache' (public)

Example - This will error:

// ❌ ERROR: "use cache: private" must not be used within "use cache". 
// It can only be nested inside of another "use cache: private".

export default async function Page() {
  'use cache'  // public cache
  
  return <Child />
}

async function Child() {
  'use cache: private'  // ❌ Cannot nest private in public
  return <div>...</div>
}

Example - This will work:

// ✅ OK: private cache nested in private cache

async function Parent() {
  'use cache: private'
  
  return <Child />
}

async function Child() {
  'use cache: private'  // ✅ OK to nest private in private
  return <div>...</div>
}

###2. Conditional Static Generation - Make Some Routes Always Dynamic

You have two approaches:

This completely opts a route out of static generation, even if generateStaticParams returns values for it:

// app/blog/[slug]/page.tsx

export const dynamic = 'force-dynamic'

export async function generateStaticParams() {
  return [
    { slug: 'post-1' },
    { slug: 'post-2' },
    { slug: 'post-3' },
  ]
}

export default async function Page({ params }: { params: { slug: string } }) {
  // This route is ALWAYS dynamic, never prerendered
  // Even though generateStaticParams has values
  const data = await fetch(`/api/posts/${params.slug}`)
  return <div>{data}</div>
}

Use force-dynamic when:

  • Routes need to be generated on-demand (e.g., user-specific content)
  • You have generateStaticParams for fallback/prefetching but don't want build-time prerendering
  • Routes depend on dynamic request data (cookies, headers, search params)

####Option B: Use dynamicParams = false + selective generateStaticParams

Return only the routes you want prerendered from generateStaticParams:

// app/blog/[slug]/page.tsx

export const dynamicParams = false  // Block routes not in generateStaticParams

export async function generateStaticParams() {
  // Only these specific slugs are prerendered
  return [
    { slug: 'featured-post-1' },
    { slug: 'featured-post-2' },
  ]
  // All other routes (e.g., /blog/random-slug) → 404
}

export default async function Page({ params }: { params: { slug: string } }) {
  const data = await fetch(`/api/posts/${params.slug}`)
  return <div>{data}</div>
}

Use dynamicParams = false when:

  • You want a whitelist of prerendered routes
  • Other routes should 404 instead of being generated on-demand
  • You have a finite, known set of valid routes

###Summary Table

ScenarioSolutionResult
Want some routes prerendered, others always dynamicexport const dynamic = 'force-dynamic'Routes never prerendered, always SSR
Want only specific routes prerenderedexport const dynamicParams = false + return specific slugs from generateStaticParamsOnly those routes prerendered; others 404
Child has 'use cache', parent has 'use cache: private'Not allowedRuntime error
Child has 'use cache: private', parent has 'use cache: private'AllowedWorks correctly

Source files:


END OF POST

Cache inheritance and conditional static generation in Next.js? — vercel/next.js