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.
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.
revalidate
Replace with cacheLife. Use the cacheLife function to define cache duration instead of the route segment config.
fetchCache
Not needed. With use cache, all data fetching within a cached scope is automatically cached, making fetchCache unnecessary.
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
useLayoutEffectcleanup 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
useActionStateresults (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.