Migrating to Cache Components

Learn how to migrate from route segment configs to Cache Components in Next.js.

When Cache Components is enabled, route segment configs like dynamic, revalidate, and fetchCache are replaced by use cache and cacheLife.

dynamic = "force-dynamic"

Not needed. All pages are dynamic by default.

// Before - No longer needed
export const dynamic = 'force-dynamic'
 
export default function Page() {
  return <div>...</div>
}
// After - Just remove it
export default function Page() {
  return <div>...</div>
}

dynamic = "force-static"

Start by removing it. When unhandled uncached or runtime data access is detected during development and build time, Next.js raises an error. Otherwise, the prerendering step automatically extracts the static HTML shell.

For uncached data access, add use cache as close to the data access as possible with a long cacheLife like 'max' to maintain cached behavior. If needed, add it at the top of the page or layout.

For runtime data access (cookies(), headers(), etc.), errors will direct you to wrap it with <Suspense>. Since you started by using force-static, you must remove the runtime data access to prevent any request time work.

// Before
export const dynamic = 'force-static'
 
export default async function Page() {
  const data = await fetch('https://api.example.com/data')
  return <div>...</div>
}
import { cacheLife } from 'next/cache'
 
// After - Use 'use cache' instead
export default async function Page() {
  'use cache'
  cacheLife('max')
  const data = await fetch('https://api.example.com/data')
  return <div>...</div>
}

revalidate

Replace with cacheLife. Use the cacheLife function to define cache duration instead of the route segment config.

// Before
export const revalidate = 3600 // 1 hour
 
export default async function Page() {
  return <div>...</div>
}
// After - Use cacheLife
import { cacheLife } from 'next/cache'
 
export default async function Page() {
  'use cache'
  cacheLife('hours')
  return <div>...</div>
}

fetchCache

Not needed. With use cache, all data fetching within a cached scope is automatically cached, making fetchCache unnecessary.

// Before
export const fetchCache = 'force-cache'
// After - Use 'use cache' to control caching behavior
export default async function Page() {
  'use cache'
  // All fetches here are cached
  return <div>...</div>
}

runtime = 'edge'

Not supported. Cache Components requires the Node.js runtime. Switch to the Node.js runtime (the default) by removing the deprecated runtime = 'edge' export. If you need edge behavior for specific routes, use Proxy instead.

UI state preservation

Component state now persists across navigations. With Cache Components, Next.js preserves routes using React's <Activity> component in "hidden" mode instead of unmounting them. Effects clean up and re-run normally, but useState values, form inputs, and scroll position are no longer reset when navigating away and back.

If your code relied on unmounting to clear state, you may need to add explicit reset logic:

  • Dropdowns and popovers — stay open when navigating back. Close them in a useLayoutEffect cleanup function.
  • Dialogs with initialization logic — Effects that depend on dialog state (like focusing an input) won't re-fire if the state was preserved. Derive dialog state from the URL instead.
  • Forms after submission — input values and useActionState results (success/error messages) persist when returning. Reset in the submit handler or user action when possible, otherwise use a cleanup effect.

See Preserving UI state across navigations for detailed examples of each pattern.

On this page