Skip to content

Route Segment Config and Runtimes

Route Segment Config is a set of file-level export const values that let you override how a single route segment renders, caches, and which runtime it runs on.

Each of these is a named export at the top of a layout.tsx, page.tsx, or route.ts. They apply to that segment and its children.

app/blog/page.tsx
export const dynamic = 'auto'; // 'auto' | 'force-dynamic' | 'error' | 'force-static'
export const revalidate = 3600; // ISR: rebuild this route at most once per hour
export const runtime = 'nodejs'; // 'nodejs' (default) | 'edge' (deprecated)
export const fetchCache = 'auto'; // control the default caching of fetch() in this segment
export const dynamicParams = true; // allow params not returned by generateStaticParams
  • dynamic — force the rendering mode; 'force-dynamic' renders every request, 'force-static' forbids dynamic APIs.
  • revalidate — seconds between background rebuilds; this is how you turn on ISR.
  • runtime — the execution environment, 'nodejs' (default) or 'edge' (deprecated in Next.js 16).
  • fetchCache — override how fetch() calls in the segment are cached by default.
  • dynamicParams — when false, a param not listed by generateStaticParams returns a 404 instead of being rendered on demand.

Every route runs on the default Node.js runtime, which gives you the full Node API surface. The Edge runtime is a smaller, Web-API-only environment. Since Next.js 16 it is deprecated as a route runtime: next build prints The Edge Runtime is deprecated for any page that exports it, and Cache Components rejects the export outright — for either value, not just 'edge' (proven below). Edge lives on for proxy.ts (the file formerly known as Middleware).

// Opt a route into the Edge runtime — deprecated since Next.js 16: next build warns, Cache Components rejects it
export const runtime = 'edge';

What that means in practice:

  • Node.js (default) — full Node APIs, native modules, larger libraries, database drivers, and the only runtime that supports ISR and Cache Components. Leave the runtime export out and this is what you get.
  • Edge — a limited API set (no filesystem, no native modules, no require), no ISR, and a deprecation warning at build. If you need edge-style logic such as redirects or lightweight auth checks, put it in proxy.ts rather than on a route.

Incremental Static Regeneration keeps a route static and fast while still letting it go stale and refresh on a timer. Set revalidate to a number of seconds and Next.js serves the cached static page, then rebuilds it in the background after that window.

app/products/page.tsx
export const revalidate = 60;
export default async function Products() {
const products: { id: number; name: string }[] = await fetch('https://api.example.com/products').then((r) => r.json());
return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>;
}

The first request after 60 seconds triggers a background rebuild; visitors keep getting the fast cached page until the fresh one is ready.

Under cacheComponents: true the revalidate export is rejected. The equivalent is a 'use cache' scope with a cacheLife profile — next build then lists the route as ○ /products 1m 1h:

app/products-cc/page.tsx
import { cacheLife } from 'next/cache';
export default async function Products() {
'use cache';
cacheLife('minutes'); // stale 5m, revalidate 1m, expire 1h — closest preset to revalidate = 60
const products: { id: number; name: string }[] = await fetch('https://api.example.com/products').then((r) => r.json());
return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>;
}

Every incompatible export produces the exact same shape of error under cacheComponents: true — confirmed one at a time in the probe, real messages, only the file path trimmed:

Error: Route segment config "dynamic" is not compatible with `nextConfig.cacheComponents`. Please remove it.
Error: Route segment config "revalidate" is not compatible with `nextConfig.cacheComponents`. Please remove it.
Error: Route segment config "fetchCache" is not compatible with `nextConfig.cacheComponents`. Please remove it.
Error: Route segment config "dynamicParams" is not compatible with `nextConfig.cacheComponents`. Please remove it.
Error: Route segment config "runtime" is not compatible with `nextConfig.cacheComponents`. Please remove it.
Error: Route segment config "experimental_ppr" is not compatible with `nextConfig.cacheComponents`. Please remove it.

preferredRegion and maxDuration are not on that list — built with cacheComponents: true and both exports present, the build succeeds. preferredRegion prints its own, unrelated deprecation warning (it’s deprecated everywhere, with or without Cache Components); maxDuration builds silently, with no warning at all:

⚠ The "preferredRegion" route segment config is deprecated. Learn more: https://nextjs.org/docs/messages/preferred-region-deprecated
ExportUnder Cache ComponentsEquivalent
dynamic = 'force-dynamic'Rejected — build errorNot needed; every route is dynamic by default. Wrap the parts that need prerendering in 'use cache' instead.
dynamic = 'force-static'Rejected — build error'use cache' with a long cacheLife (e.g. 'max') for the uncached data; move any request-time API into a <Suspense> boundary.
revalidateRejected — build errorcacheLife(...) inside a 'use cache' scope — pick the closest built-in profile ('seconds'…'max') or define a custom one.
fetchCacheRejected — build errorNot needed — every fetch() inside a 'use cache' scope is cached automatically.
dynamicParams = falseRejected — build errorCall notFound() inside the page when a param that wasn’t returned by generateStaticParams doesn’t resolve to real data.
runtime ('nodejs' or 'edge')Rejected — build error, either valueNone — the export itself is unsupported. Cache Components requires the Node.js runtime; there is nothing left to configure.
preferredRegionBuilds fine — unrelated deprecation warning onlyNone — deprecated independently of Cache Components. Remove it regardless and let the deployment platform pick a region.
maxDurationBuilds fine — no warningNone needed — it’s a deployment-platform execution-time hint, orthogonal to caching, and stays exactly as it was.
experimental_ppr = trueRejected — build errorNot needed; PPR is the default behavior the moment cacheComponents: true is set.
flowchart TD
  A[Route segment config] --> B[dynamic]
  A --> C[revalidate for ISR]
  A --> D[runtime]
  D --> E[nodejs, full APIs, default]
  D --> F[edge, deprecated in 16, limited APIs, no ISR]
Route segment config and the two runtimes

Route Segment Config is a set of dials on the outside of a file — you never touch the render body to change caching or runtime, you just add an export const at the top. Cache Components removes every one of those dials except two (preferredRegion, maxDuration, both deployment hints that have nothing to do with caching) and replaces the rest with decisions made inside the function body instead — 'use cache' and cacheLife(...) sit next to the code they affect, rather than declaring a blanket policy for the whole file from outside it.

What you getBenefitCost
Route Segment Config (previous model)One line per concern, declared at the top of the file, easy to scanA blanket, file-wide setting — can’t cache one fetch differently from another in the same segment
'use cache' + cacheLife (Cache Components)Caching decisions live next to the code they cache, at whatever granularity you choose (function, component, page)More to read inside the function body; no single top-of-file summary of the segment’s caching policy
Leaving runtime unsetFull Node.js API surface, compatible with Cache ComponentsCan’t opt into Edge’s smaller cold-start footprint on a route (Edge is deprecated anyway)
Removing preferredRegion/maxDuration when not neededOne less config surface to keep in sync with deployment realityNone — these two never conflicted with Cache Components in the first place
  • Cache Components only rejects runtime = 'edge', since that’s the deprecated value. It rejects the runtime export itself, for either value — runtime = 'nodejs' fails exactly the same way, because Cache Components requires Node.js and there’s nothing left to configure.
  • preferredRegion and maxDuration must also be migrated to 'use cache'/cacheLife. They’re not caching config at all — they’re deployment-platform hints (region, execution time limit) and Cache Components doesn’t touch them. preferredRegion is deprecated for unrelated reasons; maxDuration isn’t deprecated at all.
  • dynamicParams = false has no replacement under Cache Components. It does — call notFound() inside the page itself when an unlisted param doesn’t correspond to real data, rather than declaring the 404 behavior as a blanket file-level export.
  • Removing experimental_ppr = true turns PPR off. The opposite — that export (and the matching experimental.ppr config flag) was removed because PPR became the default behavior of cacheComponents: true; there’s no way to have cacheComponents on without PPR active.

When a generated snippet exports Route Segment Config, check for these before trusting it:

  • Does the project have cacheComponents: true in next.config.ts, while a page still exports dynamic, revalidate, fetchCache, dynamicParams, runtime, or experimental_ppr? Every one of those fails the build outright — this is a build-time signal, not a subtle bug, but AI-generated code is often written (or copy-pasted from an older example) without checking the project’s actual config.
  • Does the code set runtime = 'nodejs' explicitly, assuming that’s always harmless because it’s the default? Under Cache Components, exporting it at all — even the default value — is rejected.
  • Does dynamicParams = false appear anywhere in a Cache Components project? It needs to become a notFound() call inside the component instead.
  • Is preferredRegion or maxDuration being “migrated” to cacheLife or 'use cache' unnecessarily, when neither one is actually incompatible with Cache Components?
  • Does old documentation or a stale example still reference experimental.ppr or experimental_ppr as if it needs to be set for PPR to work in Next.js 16? Both were removed — PPR is on whenever cacheComponents: true is.

🐛 Spot the bug

next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
}
export default nextConfig
// app/dashboard/page.tsx
export const dynamic = 'force-dynamic'
export default function Dashboard() {
return <div>Dashboard</div>
}
Show the answer

cacheComponents: true and export const dynamic = 'force-dynamic' cannot coexist. The build fails with Route segment config "dynamic" is not compatible with nextConfig.cacheComponents. Please remove it. — under Cache Components every route is already dynamic by default, so force-dynamic isn’t just redundant, it’s a rejected export. The fix is to delete the dynamic export entirely; if part of the page genuinely needs to be static (or cached), wrap that part in 'use cache' instead of declaring a file-wide mode from outside the component.

Where do Route Segment Config values live?
Which export turns on Incremental Static Regeneration?
What is the default runtime for a route?
What is the status of export const runtime = 'edge' in Next.js 16?
Does this build?
// next.config.ts
const nextConfig = { cacheComponents: true }
// app/page.tsx
export const runtime = 'nodejs'
Which two Route Segment Config exports build successfully under cacheComponents: true, with no Cache Components equivalent needed?
What is the Cache Components-compatible replacement for this line?
export const dynamicParams = false

export default function Page() { /* ... */ }