new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Next.js App Router · all subjects

cache components & streaming

43 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Cache Components prerequisite: cacheComponents config

To use Cache Components with authentication, enable the cacheComponents flag in next.config.ts: `const nextConfig: NextConfig = { cacheComponents: true }`

What is Cache Components feature

Cache Components is a feature that enables session reads to happen at request time without being prerendered into the static shell. With Cache Components enabled, authenticated UI streams in behind a Suspense boundary, and data derived from the session can still be cached. Session reads can't be prerendered into the static shell, so they always sit behind a Suspense boundary and stream in on every navigation.

When to use Cache Components

Use Cache Components when you need to read the user session at request time, show authenticated UI without blocking the page, and cache data derived from the session. Cache Components enable you to prefetch authenticated content ahead of time by adding a cache lifetime to session reads.

use cache: private accepts only specific runtime functions

The 'use cache: private' directive accepts cookies(), headers(), and searchParams, but not connection().

How to show authenticated UI without blocking the page

Place a component that reads the session behind a Suspense boundary. With Cache Components, reading cookies() outside a boundary is a build error. The boundary keeps the rest of the page fast because anything outside it prerenders into the static shell and loads instantly if it's static or wrapped in 'use cache' and doesn't read runtime data. Only the section behind the boundary waits for the request.

Making authenticated navigations instant with Cache Components

Cached reads already have a lifetime, so instant navigation mostly happens automatically. A 'use cache: private' scope uses the default profile (five-minute stale) unless you set one, and a route that reads the session produces a per-session App Shell with authenticated content that is prefetched and cached per session. Navigations to it are instant if you keep stale at 30 seconds or more and use Link prefetch={true} for routes depending on URL parameters.

Common pitfall: reading cookies in plain use cache

Reading cookies() or headers() inside a plain 'use cache' function throws a build error. Read the request outside and pass the value in, or use 'use cache: private' instead.

Cache Components feature definition and purpose

Cache Components is a feature enabled via the cacheComponents configuration option that works with Partial Prefetching to implement Incremental Static Regeneration (ISR) in the App Router. It gives every route an instant first visit by splitting the render into two parts: the App Shell (generic, reusable part that doesn't depend on URL data) and param-specific prerendered content. For URLs whose params were included in generateStaticParams, Next.js serves the fully prerendered page from cache. For URLs whose params weren't prerendered, Next.js serves the App Shell instantly, then upgrades it in the background with the now-known params.

When to use Cache Components

Use Cache Components for routes where you want instant first visits even for unknown URL parameters. It is particularly beneficial for frequently visited routes or when you want to serve dynamic content that may not have all param combinations prerendered. Cache Components is the App Router equivalent of ISR or fallback: true from the Pages Router.

generateStaticParams defines which params to prerender

Use generateStaticParams to define which param values are prerendered at build time. The function returns an array of objects where each object represents a param combination. When rendering routes listed in generateStaticParams, param values are known at build time, and the prerender process builds a static shell until it hits runtime APIs or uncached data.

Using Suspense with params in Cache Components

When using Cache Components, do not await props.params at the layout level. Instead, pass the params promise to a child component inside a Suspense boundary and await params inside the boundary. This allows Next.js to generate the App Shell for unknown params. Keep the read inside the boundary even for categories that generateStaticParams covers, because a statically known param belongs to one URL, and awaiting it above the Suspense boundary would tie the layout's App Shell to that specific URL.

Runtime APIs with Cache Components require Suspense

If components access runtime APIs like cookies or headers, wrap them in Suspense boundaries. Their fallback UI is included in the static shell instead, allowing the App Shell to be generated without requiring these runtime APIs to complete.

App Shell generation at build time

When running next build with Cache Components, Next.js prerenders pages for each known param combination from generateStaticParams, plus one additional render where await params suspends to produce the App Shell. For dynamic routes like [category]/[product], it generates fully static pages for known combinations, App Shells for categories with unknown products, and generic App Shells when both params are unknown.

First visit behavior to unprerendered Cache Component routes

On the first visit to a URL whose params were not prerendered, Next.js immediately serves the App Shell with any prerendered parent segments already rendered. The unknown segments stream in as their content becomes available. After the first visit, Next.js renders these routes in the background with the now-known params, and subsequent visitors get the upgraded result.

Prefetch behavior with Cache Components

When a Link to an unlisted URL enters the viewport or router.prefetch is called, Next.js starts the background upgrade before the click, allowing navigation to land on the upgraded result. A prefetch counts as the first visit that triggers the background upgrade.

What upgrade produces after first visit

After the first visit to a Cache Component route, Next.js renders the page in the background with known params and tries to push the static boundary as far down the component tree as possible. If all data access is cached and all params are resolved, the upgrade produces a fully static page. If all params are resolved but the render hits uncached data or runtime APIs wrapped in Suspense boundaries, it produces a cached page with those fallbacks that stream in at request time. Params are resolved in route order, and a param value not returned by generateStaticParams stays unresolved and prevents deeper params from upgrading.

Choosing what to prerender with Cache Components

Use generateStaticParams to prerender only routes that benefit most from being ready ahead of time, such as popular pages or predictable content. Less frequently visited routes are generated on demand and upgraded after their first visit, avoiding unnecessary build work and storage for pages that may never be requested.

App Shell served from Next.js 16.3

The App Shell for unlisted params is served from Next.js 16.3 and later. Earlier versions wait for a full server render before sending the response.

Cache Components replaces route segment configs

When Cache Components is enabled, route segment configs like `dynamic`, `revalidate`, and `fetchCache` are replaced by the `use cache` directive and `cacheLife()` function.

What is Cache Components feature

Cache Components is a feature that enables instant navigation validation in development. When enabled via the `cacheComponents` flag in next.config.ts, Next.js validates whether navigating into each route renders instantly and surfaces blocking code as errors or insights. It requires Next.js 16 and replaces experimental Partial Prerendering (experimental.ppr).

use cache directive purpose

The `use cache` directive marks a function as cached. All data fetching within a cached scope is automatically cached. It replaces `fetchCache` and `unstable_cache` from the previous caching model.

dynamic = 'force-dynamic' not needed with Cache Components

All pages are dynamic by default with Cache Components. The `export const dynamic = 'force-dynamic'` config is no longer needed and should be removed.

Replace dynamic = 'force-static' with use cache

When migrating from `dynamic = 'force-static'`, remove the config and add `'use cache'` with `cacheLife('max')` to cached data access. For runtime data access like `cookies()` or `headers()`, wrap in `<Suspense>`. Synchronous IO like `new Date()` and `Math.random()` must move out of the prerendered shell.

fetchCache not needed with Cache Components

The `fetchCache` route segment config is no longer needed. With `use cache`, all data fetching within a cached scope is automatically cached, making `fetchCache` unnecessary.

Replace unstable_cache with use cache

Turn the function wrapped by `unstable_cache` into a function with the `'use cache'` directive. The cache key is derived automatically from arguments, so the key-parts array is no longer needed. The `options` object maps to `cacheLife()` and `cacheTag()` calls.

unstable_noStore not needed with Cache Components

`unstable_noStore` or `noStore()` is not needed with Cache Components. Nothing is cached unless you add `use cache`, so it can be removed. If a component must run at request time, call `connection()` before the work and wrap in `<Suspense>`.

Wrap runtime data access in Suspense

With Cache Components, reading `cookies()`, `headers()`, or `searchParams` outside a `<Suspense>` boundary surfaces a blocking-prerender-runtime insight. Move the access into a component wrapped in `<Suspense>` so the rest of the page prerenders as a static shell and the dynamic part streams in at request time.

generateMetadata with Cache Components

With Cache Components, `generateMetadata()` follows the same rules as components. If it reads runtime data or fetches uncached data while the page is prerenderable, Next.js raises an error. If metadata depends on external but not runtime data, add `'use cache'`. If metadata genuinely needs runtime data, use a dynamic marker component so static content still prerenders while metadata streams in.

runtime = 'edge' not supported with Cache Components

Cache Components requires the Node.js runtime. The `runtime = 'edge'` export is not supported and should be removed. To use edge behavior, switch to Node.js runtime (the default) or use Proxy instead for specific routes.

experimental_ppr removed in Next.js 16

Next.js 16 removes the experimental Partial Prerendering flag (`experimental.ppr`) and the `experimental_ppr` route segment config. Partial Prerendering is now part of Cache Components. Remove `experimental.ppr` from next.config and `experimental_ppr` from segments. A codemod is available to remove the segment config automatically.

instant = false defers validation for opted-out routes

Set `export const instant = false` on a segment to opt it out of instant navigation validation. This allows the whole app to build and run first, then convert routes one at a time. `instant = false` marks a segment as allowed to block but does not force the route to be dynamic. Synchronous IO build errors still occur and cannot be deferred.

Incremental adoption approach for Cache Components

The incremental approach to Cache Components migration: (1) Enable the flag and remove route segment configs. (2) Use the cache-components-instant-false codemod to add `instant = false` to every page, layout, and default that doesn't declare instant. (3) Fix synchronous IO errors (new Date(), Math.random(), crypto.randomUUID()) which cannot be deferred. (4) Convert one route at a time by removing `instant = false` and resolving insights.

Synchronous IO cannot be deferred in prerender

Calls like `new Date()`, `Date.now()`, `Math.random()`, and `crypto.randomUUID()` during prerender throw a build error that `instant = false` does not clear. Move the call out of the prerendered shell: wrap the part that needs it in `<Suspense>` and call `connection()` before the call, or move it into a Client Component.

Validation insights appear only in dev overlay

Cache Components validation insights in development only appear in the dev overlay, dev-server log, or the MCP `get_errors` tool. Insights do not show up in the HTTP response; an offending route still returns 200 with rendered HTML in dev. To see insights, read the overlay or query the MCP.

next-cache-components-adoption skill for automated migration

The `next-cache-components-adoption` skill automates Cache Components migration with a coding agent. Install with `npx skills add vercel/next.js --skill next-cache-components-adoption`. Supports incremental mode (opens single PR opting routes out of validation, then ships each feature as follow-up) and direct mode (adopts every route on one branch). Prompt the agent: 'Adopt Cache Components in this project using the next-cache-components-adoption skill.'

cache-components-instant-false codemod usage

Run `npx @next/codemod@canary cache-components-instant-false ./app` to add `instant = false` to every page, layout, and default that doesn't already declare instant. For src/ projects, pass `./src/app`. A wrong path reports `0 ok` instead of failing, so verify the file count.

Example: Migrating unstable_cache to use cache

Before: `const getUser = unstable_cache(async (id: string) => { return db.query.users.findFirst({ where: eq(users.id, id) }) }, ['user'], { tags: ['users'], revalidate: 3600 })`. After: `export async function getUser(id: string) { 'use cache'; cacheLife('hours'); cacheTag('users'); return db.query.users.findFirst({ where: eq(users.id, id) }) }`.

Example: Wrapping cookies() in Suspense

Before: `import { cookies } from 'next/hooks'; export default async function Page() { const theme = (await cookies()).get('theme')?.value; return <Dashboard theme={theme} />; }`. After: `import { cookies } from 'next/hooks'; import { Suspense } from 'react'; export default function Page() { return <Suspense fallback={<p>Loading...</p>}><Dashboard /></Suspense>; }; async function Dashboard() { const theme = (await cookies()).get('theme')?.value; ... }`.

Example: Wrapping searchParams in Suspense

Pass the `searchParams` promise to a Suspense-wrapped component: `export default function Page({ searchParams }: PageProps<'/'>) { return <Suspense fallback={<p>Loading...</p>}><Results searchParams={searchParams} /></Suspense>; }; async function Results({ searchParams }: Pick<PageProps<'/'>, 'searchParams'>) { const { query } = await searchParams; ... }`.

Example: Caching data with use cache instead of fetchCache

Before: `export const fetchCache = 'force-cache'; export default async function Page() { return <div>...</div>; }`. After: `export default async function Page() { 'use cache'; return <div>...</div>; }`.

Example: Converting force-static page with caching

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

Example: Caching external data in generateMetadata

Before: `export async function generateMetadata() { const { title, description } = await db.query('site-metadata'); return { title, description }; }`. After: `export async function generateMetadata() { 'use cache'; const { title, description } = await db.query('site-metadata'); return { title, description }; }`.

What happens during first load when user visits a Cache Component page

On the initial load, the RSC Payload ships with the HTML alongside Client Components.

Give your agent this brain