Officialvercel/next.js3 files

Next Cache Components Adoption

>

Specification
Skill ID
vercel/next.js/next-cache-components-adoption
Publisher
vercel
Repository
next.js
Installs
227
Files
3
Synced
Sep 16, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

vercel/next.js/next-cache-components-adoptionInstalls these files
  • SKILL.md
  • references/dev-only-validations.md
  • references/per-page-decisions.md

What this skill tells the agent

next-cache-components-adoption

Enable Cache Components on an app and walk it to a passing build. This skill sequences the work; per-error recipes live in the dev overlay fix cards and the build's terminal output. The migrating to Cache Components guide is the canonical reference for the concepts and per-API recipes this skill applies — consult it whenever the skill steps reference a pattern ("use cache", cacheLife, <Suspense> placement, etc.) and you want the full explanation.

requires

  • App Router project. Cache Components is an App Router feature; cacheComponents: true does nothing for pages/ routes. If the project has a pages/ or src/pages/ tree but no app/ or src/app/ tree, stop and tell the user — Pages → App migration is its own project, not part of this skill. A hybrid app (both pages/ and app/) is fine: the flag affects the app/ routes; pages/ routes are unaffected and don't need opt-outs.
  • A resolved app directory. Locate next.config.{js,ts,mjs,cjs} first: that's the project root, and an agent invoked from a subdirectory would otherwise test for app/ against the wrong cwd and find nothing. Look for app/ and src/app/ under it, and treat every command and glob in this skill as relative to whichever one exists. If both exist, Next.js builds app/ and never looks at src/app/, so its routes are shadowed and unbuilt — tell the user that and ask which tree to migrate instead of picking one.
  • A runnable app. The whole loop verifies against next dev and a browser, so the app has to boot. If it reads a database or required env at import (e.g. an env.ts that throws on a missing DATABASE_URL), confirm it actually starts — with the real environment, or local data you stand up — before step 1. Adoption can't be verified against an app that won't run.
  • Next.js 16.3 or later. That release is where the pieces this skill relies on land: top-level cacheComponents, export const instant, the dev-overlay instant-navigation validation warnings, and the cache-components-instant-false codemod. If next --version reports below 16.3, upgrade first:
  • npx @next/codemod@latest upgrade latest to apply the version-to-version codemods.
  • Read the relevant version upgrade guide (e.g. Version 16) for what the codemod doesn't cover.
  • No incompatible config keys. cacheComponents: true errors on any file that still exports dynamic, revalidate, or fetchCache. Inventory these exports before running the codemod, then follow the migration guide's per-key sections. The guide is the source of truth for translating each value. The cache-components-instant-false codemod does not remove these configs.
  • `experimental.dynamicIO` is fatal. It was renamed to top-level cacheComponents and the old key now aborts before any build can run — remove it (or replace with cacheComponents: true) first. experimental.useCache is still accepted as a deprecated alias; redundant once cacheComponents: true is set, so remove it for clarity.

notes

  • No passing baseline before the flag. If the app already uses "use cache", the pre-flag build errors with please enable the feature flag cacheComponents. Enabling the flag is the first thing you do (in Incremental, before the codemod; in Direct, before fixing routes) — not a thing to do _after_ getting a passing build. Note this in your starting summary so it doesn't read as a regression.
  • Offline docs. Guide links have offline copies under node_modules/next/dist/docs/ (bundled since Next.js 16.2), with the directory layout numbered for ordering (e.g. node_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md). If you can't predict the numbered prefix, find node_modules/next/dist/docs -name '<slug>.md' resolves it. The /docs/messages/* error pages are not bundled.
  • Older versions without bundled docs. Suggest npx @next/codemod@latest agents-md to the user before starting: it downloads a version-matched copy to .next-docs/ and writes an index into AGENTS.md / CLAUDE.md. It touches files in their repo, so ask first and run it only if they want it.

the shape of the work

There's one loop: walk the route tree top-down, one feature at a time, adopting each route against next dev + a browser. The build is a final check for each feature, not the working surface.

The choice in step 1 is whether to opt every route out of validation first or fix routes as you go. Either way the loop is the same:

  • With a quiet pre-step (Incremental). Run the codemod, fix what it can't, and fully migrate routes that previously required static rendering. Other routes keep their opt-outs for follow-up PRs.
  • Without (Direct). Enable cacheComponents and start the loop on whatever the build flags first. Same loop, but every fix sits on one branch until adoption is complete.

In both, the per-route success bar is the same: dev loop reports no errors AND `next build` passes. Check in with the user after every feature, and suggest a commit but never make one without their confirmation. Expect to spend most of the time in the loop, not in the pre-step.

background

cacheComponents: true requires every route to be prerenderable. A route that reads request-time data outside <Suspense> is "blocking" and fails the build. export const instant = false marks a route as allowed to block, which clears it in both dev and build; on a layout it covers the whole subtree during the build, but client navigations still validate each descendant segment on its own. Reads wrapped in a `"use cache"` function count as cache boundaries, not blocking reads.

When a fix introduces "use cache", follow the Caching guide for choosing a data-level or UI-level boundary and setting its lifetime and revalidating after mutations. Use the `use cache` cache-key reference when the result varies by arguments or captured values.

Three classes of blocker come up, usually in this order:

Whenever a fix introduces <Suspense>, follow the Streaming guide's granular streaming pattern and guidance for preventing CLS.

  1. Request-time reads (cookies(), headers(), await params, await searchParams). All four block when awaited at the top of a page or layout. params and searchParams often get missed because they're not framed as "request data" the way cookies and headers are. The fix is to push the read into a <Suspense>-wrapped child — and for params/searchParams, forward the promise into the child and await it there; don't await at the page top.
  2. Sync-IO at module/render time (new Date(), Date.now(), Math.random(), crypto.randomUUID()). These fail the build even with instant = false — the opt-out doesn't suppress them. If they're in a shared layout, they block every route under it. The codemod can't fix them; after running it, use each build error and its linked documentation to identify which reported calls to translate by hand (see the incremental pre-step).