Enabling Cache Components in Next.js – Migrating from Legacy Config and Controlling Dynamic Rendering

Cache Components in Next.js offer a modern way to combine dynamic rendering with fast performance. Once enabled, all pages are treated as dynamic by default, and developers can selectively cache parts of the UI using use cache and Suspense boundaries. This article explains how to enable the feature, migrate from legacy config options like dynamic and revalidate, and use new tools like cacheLife and cacheTag for precise control.

enable cacheconfig migrationcacheLifeSuspense

~3 min read • Updated Oct 25, 2025

Enabling Cache Components


To enable Cache Components, set cacheComponents: true in your next.config.ts file:


import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  cacheComponents: true,
}

export default nextConfig

Changes to Route Segment Config


  • dynamic = "force-dynamic": No longer needed. All pages are dynamic by default.
  • dynamic = "force-static": Replace with 'use cache'. Runtime APIs like cookies() are no longer allowed inside cached components.
  • revalidate: Replace with cacheLife to define cache duration.
  • fetchCache: Not needed. All fetches inside a cached scope are automatically cached.
  • runtime = 'edge': Not supported. Cache Components require Node.js runtime.

Shifting the Mental Model


Before Cache Components: Pages were static by default, and caching was controlled at the route level.

With Cache Components: Everything is dynamic by default. You decide what to cache using 'use cache' and cacheLife at the file, component, or function level.


Examples


Accessing Runtime APIs


Components using cookies() must be wrapped in <Suspense> to allow pre-rendering of the rest of the page:


// app/user.tsx
import { cookies } from 'next/headers'

export async function User() {
  const session = (await cookies()).get('session')?.value
  return '...'
}

// app/page.tsx
import { Suspense } from 'react'
import { User, AvatarSkeleton } from './user'

export default function Page() {
  return (
    <section>
      <h1>This will be pre-rendered</h1>
      <Suspense fallback={<AvatarSkeleton />}>
        <User />
      </Suspense>
    </section>
  )
}

Passing Dynamic Props


Components only become dynamic when they access the value. You can forward runtime props like searchParams without making the parent dynamic:


// app/page.tsx
import { Table, TableSkeleton } from './table'
import { Suspense } from 'react'

export default function Page({ searchParams }) {
  return (
    <section>
      <h1>This will be pre-rendered</h1>
      <Suspense fallback={<TableSkeleton />}>
        <Table sortPromise={searchParams.then((s) => s.sort)} />
      </Suspense>
    </section>
  )
}

Frequently Asked Questions


Does this replace Partial Prerendering (PPR)?


No. Cache Components implement PPR as a feature. The old experimental flag is gone, but PPR remains active.


What should I cache first?


Cache data that doesn’t rely on runtime APIs and can be reused across requests. Use 'use cache' with cacheLife to define behavior.


How do I update cached content quickly?


Use cacheTag to tag cached data, then trigger updateTag or revalidateTag to refresh it.


Written & researched by Dr. Shahin Siami