[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-vercel-next-partial-prefetching-adoption":3,"mdc-p5jsb0-key":47,"related-repo-vercel-next-partial-prefetching-adoption":1950,"related-org-vercel-next-partial-prefetching-adoption":2004},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":42,"sourceUrl":45,"mdContent":46},"next-partial-prefetching-adoption","adopt Partial Prefetching in Next.js apps","Turn on Partial Prefetching in a Next.js app and work through the insights it surfaces. Use when the user wants to enable or adopt Partial Prefetching, flip the `partialPrefetching` flag, opt routes in with `export const prefetch = 'partial'`, audit `\u003CLink prefetch={true}>` calls, or resolve the link-prefetch-partial and instant-shell-url-data insights.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"vercel","Vercel","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fvercel.png",[12,16,17,20],{"name":13,"slug":14,"type":15},"Performance","performance","tag",{"name":9,"slug":8,"type":15},{"name":18,"slug":19,"type":15},"Next.js","next-js",{"name":21,"slug":22,"type":15},"Frontend","frontend",141208,"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js","2026-07-30T05:31:11.591864",null,31587,[29,30,31,32,33,34,35,36,37,38,39,40,41,8],"blog","browser","compiler","components","hybrid","nextjs","node","react","server-rendering","ssg","static","static-site-generator","universal",{"repoUrl":24,"stars":23,"forks":27,"topics":43,"description":44},[29,30,31,32,33,34,35,36,37,38,39,40,41,8],"The React Framework","https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002FHEAD\u002Fskills\u002Fnext-partial-prefetching-adoption","---\nname: next-partial-prefetching-adoption\ndescription: >\n  Turn on Partial Prefetching in a Next.js app and work through the\n  insights it surfaces. Use when the user wants to enable or adopt\n  Partial Prefetching, flip the `partialPrefetching` flag, opt routes\n  in with `export const prefetch = 'partial'`, audit\n  `\u003CLink prefetch={true}>` calls, or resolve the\n  link-prefetch-partial and instant-shell-url-data insights.\n---\n\n# next-partial-prefetching-adoption\n\nEnable Partial Prefetching and walk the app until every link reuses a shared App Shell. This skill sequences the work; per-insight recipes live in the dev overlay fix cards and their docs pages. The [Adopting Partial Prefetching guide](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching) is the canonical reference for the concepts this skill applies.\n\nThe one thing that shapes everything below: **these insights surface only in `next dev`, in the dev overlay's Insights tab.** Nothing fails the build. There is no build-only fallback loop — confirming an insight is _cleared_ means driving the running app in a browser. But a missing browser gates that verification, not the whole skill: the adoption work is static and runs from the guide, so do the static pass anyway and hand off the live shell check.\n\nTalk to the user in terms of what they'll see — PRs, features, and how the app behaves after — never the insight slugs or step labels. Before you start, tell them briefly what Partial Prefetching changes: a `\u003CLink>` loads a shared App Shell, and `prefetch={true}` no longer prefetches everything the old full prefetch did.\n\n## requires\n\n- **Cache Components on (`cacheComponents: true`).** This is the only hard requirement; `partialPrefetching` depends on it. Full Cache Components adoption is the ideal starting point but not a gate. Nothing in this skill blocks the build, and neither do the prerender insights an unadopted route surfaces, like a leftover `unstable_noStore` or a `cookies()` read outside `\u003CSuspense>`: they are non-blocking dev signals, expected on any fresh branch off `main`, not a reason to stop. They replace the URL-data insight only on their own route in the [step 3](#step-3-sweep-for-url-data-insights-after-enabling) sweep; the flag-off step 1 audit and its static adoption run regardless. The only thing that actually stops this skill is a build-blocking failure, and anything build-blocking would have been resolved before you reached here. Otherwise fix the prerender insights you hit as inline [`next-cache-components-adoption`](https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-cache-components-adoption) work, or hand them off, and keep going.\n\n- **Next.js 16.3 or later.** `partialPrefetching`, the `prefetch` route segment config, and the prefetch insights all land there.\n\n- **A browser you can drive.** Install [`next-dev-loop`](https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-dev-loop) before starting (`npx skills add https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-dev-loop`). Install it without asking — it's a tool, not a product change — and don't assume it's blocked: verify a real blocker (no network, no npm, read-only filesystem) before falling back, and name it in your report. Link prefetches fire when a link renders and enters the viewport, and shell validation fires on navigation — neither is reachable from `curl` or the build. If the app is webpack-pinned, drive a browser directly (`agent-browser`, Playwright) — you lose the framework cross-checks, not the insights; they're still in the overlay and the dev log.\n\n- **A runnable app.** Verification runs against `next dev` for the insight sweep and a production `next build`\u002F`next start` for prefetching (prefetching is prod-only), so the app has to boot in both. If it reads a database or required env at import (e.g. an `env.ts` that throws on a missing `DATABASE_URL`), confirm it starts — with the real environment, or local data you stand up — before step 1. An app that won't run can't be swept or verified.\n\n### notes\n\n- **Offline docs.** Guide links have offline copies under `node_modules\u002Fnext\u002Fdist\u002Fdocs\u002F` (bundled since Next.js 16.2), with the directory layout numbered for ordering (e.g. `node_modules\u002Fnext\u002Fdist\u002Fdocs\u002F01-app\u002F02-guides\u002Fadopting-partial-prefetching.md`). If you can't predict the numbered prefix, `find node_modules\u002Fnext\u002Fdist\u002Fdocs -name '\u003Cslug>.md'` resolves it. The `\u002Fdocs\u002Fmessages\u002F*` error pages are not bundled.\n\n- **Older versions without bundled docs.** Suggest `npx @next\u002Fcodemod@latest agents-md` to the user before starting: it downloads a version-matched copy to `.next-docs\u002F` and writes an index into `AGENTS.md` \u002F `CLAUDE.md`. It touches files in their repo, so ask first and run it only if they want it.\n\n## background\n\nAdopting Partial Prefetching means every route still delivers what its links prefetched before, now split between the shared App Shell and any extra per-link data a link explicitly asks for. The [guide](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching) is the canonical reference for what a prefetch contains and how to decide each case; this skill sequences that work against a running app.\n\nThe catch that decides most of the sweep: a default link warms only the shared App Shell. A route keyed by `params` or `searchParams` can prefetch more only after it has adopted Partial Prefetching and a specific link uses [`\u003CLink prefetch={true}>`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fcomponents\u002Flink#prefetch); then Next.js resolves the URL data and any cached content behind it before the click (the guide's [URL data](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching#url-data) section).\n\n## working surfaces\n\n- **The dev server terminal — your primary record.** Each validated route's insights are logged as `Error: Route \"...\": Next.js encountered ...` lines with the `https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002F\u003Cslug>` link. Tail the dev log during the sweep; it's the greppable record of what fired where, and it works the same on Turbopack and webpack.\n- **The dev overlay Insights tab.** Insights are the amber, non-blocking tab. It appears only once an insight has fired, so a route that surfaces nothing shows no tab at all — that's the clean state, not a missing feature. Don't hunt for the tab on a quiet route; confirm clean from the dev log above, which is the reliable signal. The precondition is no blocking-prerender errors — those replace the insight on their route (see requires). An unrelated Issue (a hydration error, a console error) doesn't block the sweep; don't stall on it. When the tab is present, the overlay pill shows the count and each insight has fix cards linking its docs page. The overlay renders inside a shadow root (`nextjs-portal`), so accessibility-tree snapshots don't see it — evaluate into `shadowRoot` when you need to read or click it programmatically.\n- **`next-dev-loop`** to drive navigations and read the overlay. Prefer it over hand-rolled browser automation for the same reasons as in the Cache Components skill (webpack apps: see requires). When browsing its `\u002F_next\u002Fmcp` tools, the prefetch insights surface through `get_errors` and the overlay, not the similarly-named `get_request_insights`. That one is the span and performance recorder (gated behind `experimental.requestInsights`) and reports nothing about prefetching.\n\nEvery insight has a docs page — open it. Fetch the linked page for every distinct insight you encounter; the inline message is a summary, the page is the recipe.\n\n## step 1: audit `\u003CLink prefetch={true}>` (before enabling)\n\nIf `partialPrefetching: true` is already set in `next.config.ts`, the app is adopted — skip to [step 3](#step-3-sweep-for-url-data-insights-after-enabling). Otherwise work the audit with the global flag **off**, adopting each destination with `export const prefetch = 'partial'` — enabling the flag first would mark every route adopted and silence the [`link-prefetch-partial`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Finstant-link-prefetch-partial) insight this audit runs on. Ask the user how to ship it, in the language of PRs:\n\n- **One branch** — the whole audit in one change, with the flag enabled and the codemod run at the end (step 2).\n- **Route by route** — each adopted destination ships as its own PR. The insight still fires for the destinations you haven't reached, a live worklist, and step 2 comes after the last one.\n\nThe work is identical either way — only the commit boundaries differ. Default by app size: one branch for a handful of links, route by route when the audit is big enough that reviewers need smaller diffs. Note the choice in your report.\n\nEnumerate the prefetch sites across the whole source tree, not only `app\u002F` — they often live in `src\u002Fcomponents` or shared UI packages: `rg -n '\\bprefetch\\b|router\\.prefetch' -g '*.tsx' -g '*.jsx' .`. Keep the `\u003CLink prefetch={true}>` and bare-prop matches (a bare prop is `true`) as the over-prefetching links this audit adopts destinations for, and drop `prefetch={false}` and other values. Also audit existing imperative [`router.prefetch()`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Ffunctions\u002Fuse-router#userouter) call sites with the same table, because they can be preserving the same \"fetch before navigation\" behavior and have no dev insight. For new navigation prefetching, prefer [`\u003CLink>`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fcomponents\u002Flink), which the docs call the primary navigation API; use [`router.prefetch()`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fprefetching#manual-prefetch) only for manual prefetching. If the app already passes an internal `kind` option, treat that as existing implementation detail, not a pattern to spread. If nothing matches, check for a custom link wrapper before calling the audit empty. If there's still nothing, say so in your report and move on to [step 2](#step-2-enable-the-flag).\n\nThen, for each one:\n\n1. **Click each `\u003CLink>` in `next dev`.** The insight fires at navigation time, not when the link prefetches, so a link sitting in the viewport won't trip it — you have to navigate through it. This click is _verification_: it confirms the insight fires before you adopt and clears after. Imperative `router.prefetch()` sites have no equivalent insight, so audit them from source and verify them in production ([step 4](#step-4-verify)). Without a browser, skip the click and adopt from [`link-prefetch-partial`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Finstant-link-prefetch-partial) and the audit table below — the destination's structure tells you the row, and type-check gates the edit — then leave the live confirmation for the hand-off.\n2. **Adopt the destination.** Add `export const prefetch = 'partial'`. That clears the insight for every link pointing at it. If the route reads URL data (`params`, `searchParams`), the default link still warms only its skeleton (the guide's [URL data](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching#url-data) section), so it's a runtime-prefetch candidate for step 5, not a finished adoption. Keep `prefetch={true}` on its links and mark the route:\n\n   ```tsx\n   \u002F\u002F TODO(runtime-prefetch): assess with the user whether URL data should resolve before click.\n   export const prefetch = 'partial'\n   ```\n\n   Use that exact prefix so step 5 can grep them back. Don't cache or decide anything for these routes now.\n\n3. **Preserve what that prefetch delivered.** The guide's [audit table](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching#auditing-link-prefetchtrue-calls) is the canonical decision — fetch it and apply the matching row rather than re-deriving it. Caching uncached content is the judgment call in that table: trace where the data comes from and what freshness and revalidation it needs, per the [`use cache`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fdirectives\u002Fuse-cache) docs, and ask the user when the answer isn't clear-cut. The URL-data routes you marked in the previous item wait for step 5.\n\n> **If you add `use cache`, verify under `next start`, not only the build.** A `cookies()`\u002F`headers()`\u002Fsession read anywhere in the cached call tree throws at request time while `next build` passes clean. See [`use cache`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fdirectives\u002Fuse-cache).\n\n## step 2: enable the flag\n\nOnce every audited destination has `prefetch = 'partial'`, finish in two moves.\n\n1. **Enable the flag globally.** Set `partialPrefetching: true` in `next.config.ts` (alongside `cacheComponents: true`). Every route is adopted now, so every link is good.\n2. **Strip the redundant `prefetch = 'partial'` exports.** Run the first-party `remove-partial-prefetch` codemod rather than a text find-and-replace. It removes only `export const prefetch = 'partial'` and leaves other values such as `prefetch = 'force-disabled'` in place, along with your `TODO(runtime-prefetch)` markers, which wait for step 5.\n\n   Use the `@canary` channel, not `@latest`. The `remove-partial-prefetch` transform isn't in the stable `@next\u002Fcodemod` release yet, and `@next\u002Fcodemod@latest` errors with `Invalid transform choice`.\n\n   ```bash\n   npx @next\u002Fcodemod@canary remove-partial-prefetch .\u002Fapp\n   ```\n\n   The codemod refuses to run on a dirty working tree. Commit or stash unrelated work first, or pass `--force` to let its edits land alongside your WIP. If the codemod isn't available (older `@next\u002Fcodemod`, sandboxed environment, offline run), reproduce it by hand by removing `export const prefetch = 'partial'` from every `app\u002F**\u002F{page,layout}.{js,jsx,ts,tsx}` — leave other `prefetch` values in place, and leave the `TODO(runtime-prefetch)` markers where they are. Don't hand-edit when the codemod can run.\n\n## step 3: sweep for URL-data insights (after enabling)\n\nThis is a dev-only second pass. The shell check runs only with the flag on, fires at navigation time, and never blocks the build, so it can happen any time after step 2. Build the route queue from a concrete source (the last `next build` route table, or the `app\u002F` tree) and keep it as a todo list.\n\nSweep feature by feature. A feature is a single product surface — `app\u002Fsettings\u002F**`, `app\u002Fposts\u002F[slug]\u002F**` — not a whole top-level area. Finish one end-to-end before starting the next: load its routes in `next dev` and resolve their insights. The insight never blocks the build and each route is independent, so a partial sweep leaves a working app, and each feature is a self-contained change the user can review or ship on its own.\n\nIf the environment can't finish the whole sweep (slow first compiles, a dev server that falls over under load, no browser at all), take the browser-free work as far as it goes before handing off. Adopt every route you can statically: apply the fix from [`URL data`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Finstant-shell-url-data) (up to a new `\u003CSuspense>` boundary) and opt the route into `prefetch = 'partial'`, gating on type-check. Work the whole queue in one pass — a larger refactor isn't a reason to defer, and asking whether to continue to the next route or tier isn't a checkpoint; keep going. Stop only for a genuine judgment call, and batch those into the single hand-off report: the routes you statically adopted, the ones still needing a live shell check, and the queue.\n\nWatch the Insights tab and the dev log for `Next.js encountered … data` lines. The signal this step adds is [`URL data`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Finstant-shell-url-data): a `params` or `searchParams` read too high in the suspended subtree ties the shared shell to one URL. This insight is narrow; it most reliably appears on a `generateStaticParams` route where `params` is already under `\u003CSuspense>`, but still awaited before the URL-specific leaf boundary. If a `blocking-prerender-*` error fires instead, apply the same structural fix.\n\nLoading a route with the flag on prerenders its App Shell, which validates more of the route than the Cache Components build did. So a route that built cleanly under Cache Components (every route `◐`, no errors) can still surface a `blocking-prerender-*` error here the first time its shell is prerendered — [`runtime data`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Fblocking-prerender-runtime) (`cookies()`\u002F`headers()`), [`uncached data`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Fblocking-prerender-dynamic) (an uncached `fetch`\u002FDB call), or sync IO like `Date.now()`\u002F`new Date()`. This doesn't mean the Cache Components adoption was incomplete; it's new validation reaching a path the build never exercised. These aren't Partial Prefetching insights — fix each one the same way you would any blocking-prerender error.\n\nThese fixes rarely involve the user — each insight names the offending read and its docs page has the fix, so apply it and keep sweeping. Collect the rare exceptions for one batched question at the end: a page that is entirely one URL-dependent region (wrapping it all leaves an empty shell), or a route that should arguably stay opted out. Don't narrate the refactor with comments — the `\u003CSuspense>` boundaries speak for themselves.\n\n## step 4: verify\n\nChecklist before checking in with the user:\n\n- **An empty sweep is expected when Cache Components adoption finished cleanly.** A quiet log is success, not a missing signal. If you deliberately probe the validation path, use a `generateStaticParams` route with `params` read inside `\u003CSuspense>` but before the URL-specific leaf boundary; other shapes may surface `blocking-prerender-*` instead.\n- The App Shells are real: for each route you changed, confirm the first paint after a navigation shows the intended shared content, not an empty shell or a stuck fallback. A `\u003CSuspense>` around the whole page body passes validation with an empty shell, which defeats the point.\n- The insights validate shell _structure_, not that a prefetch actually happened. Confirm on the production run (prefetching is prod-only) that navigating a changed link lands on the shared shell instantly.\n- **If the app prefetches imperatively**, the insight sweep does not cover it, so an empty sweep is not proof the prefetch survived the flag. Verify the call under `next start`: compare the `_rsc` prefetch response or resource timing before\u002Fafter, and make sure any intentionally preserved full prefetch still carries the data the old call was warming. If it now returns only the App Shell, migrate that call site using the same decision as the nearest `\u003CLink prefetch={true}>` destination — cache the data, or move runtime-prefetch behavior to a docs-supported `\u003CLink prefetch={true}>`.\n- **Before blaming a broken route on the flag, reproduce it with `partialPrefetching` off** (or on the pre-flag branch). The flag surfaces existing issues — a fragile request-time auth gate, a rewrite, deployment skew — earlier and more visibly, but rarely causes them. If it breaks flag-off too, it isn't a Partial Prefetching problem; fix it there, not here.\n- `next build` still passes.\n\nThen check in with the user. Speak their language — no insight slugs or step labels.\n\n- What you did: which links you audited, which destinations you adopted, and what each link now prefetches.\n- What changed: dropped props, `use cache` boundaries added, and which routes carry a `TODO(runtime-prefetch)` marker for later.\n- Demo against a production run. Prefetching is limited in development, so `next dev` won't show the result — run `next build` and `next start`, and hand the user that URL. That run needs the app's real environment (database, auth, secrets), and a partial or stale install or leftover generated artifacts can fail the build for reasons unrelated to the adoption. Set the expectation up front that verification is a complete, credentialed production run, not a quick check.\n- Show, don't tell: drive one link live in the headed browser against the production server, so they see the shared App Shell paint instantly and the URL-specific region stream in. Attach before\u002Fafter screenshots only when a live browser isn't possible.\n- Give them the click-through: a table of each changed route — the link to click, and what to expect after the click (what paints instantly, what streams in) — so they can verify each result themselves.\n- The question: \"Want to commit this (or open the PR) before we look at which routes should also prefetch their URL-specific content?\" Wait for the answer — adoption and runtime prefetching read best as their own changes.\n\n## step 5: runtime prefetching (optional)\n\nThe audit marked the candidates instead of deciding them. Grep for `TODO(runtime-prefetch)` and walk the list with the user in one conversation. The question per route is whether they want the URL-dependent content prefetched ahead of the click, or streaming in after navigation is fine. A runtime prefetch costs a server invocation per prefetchable link — the guide's [per-link prefetching trade-offs](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fruntime-prefetching#per-link-prefetching-trade-offs) section is the checklist. Don't make these calls alone.\n\nWhere the answer is yes, follow the [runtime prefetching guide](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fruntime-prefetching): keep [`\u003CLink prefetch={true}>`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fcomponents\u002Flink#prefetch) on the links that should resolve more than the App Shell, and cache the content behind the URL-data read using the guide's patterns (`use cache` with the runtime value passed in, or `use cache: private` for per-user data). Each per-link prefetch is a server render when the destination needs non-static data, so use the guide's [per-link trade-offs](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fruntime-prefetching#per-link-prefetching-trade-offs) to decide when viewport prefetching is worth it and when [hover-triggered prefetch](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fprefetching#hover-triggered-prefetch) is a better fit. Where it's no, delete the marker and leave the route on the App Shell default. Either way no `TODO(runtime-prefetch)` marker survives this step. Confirm the opted-in links against a production run (`next build` and `next start` — the runtime prefetch fires there, not in `next dev`), give the user the same click-through for them, and keep this as its own commit or PR.\n\n## further reading\n\n- [Instant navigation](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Finstant-navigation) — the broader validation model and loading-state tooling.\n- [Prevent regressions with e2e tests](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Finstant-navigation#prevent-regressions-with-e2e-tests) — the `@next\u002Fplaywright` `instant()` helper locks in what a navigation shows immediately; recommend it once the sweep is clean, since nothing else guards these in CI.\n- [`next-cache-components-optimizer`](https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-cache-components-optimizer) — grows each route's static shell so the App Shell carries more.\n",{"data":48,"body":49},{"name":4,"description":6},{"type":50,"children":51},"root",[52,59,76,106,127,133,338,344,431,436,449,492,498,598,603,616,671,694,699,804,809,1019,1078,1084,1097,1311,1317,1336,1363,1394,1461,1543,1555,1561,1566,1696,1701,1769,1775,1796,1880,1886,1944],{"type":53,"tag":54,"props":55,"children":56},"element","h1",{"id":4},[57],{"type":58,"value":4},"text",{"type":53,"tag":60,"props":61,"children":62},"p",{},[63,65,74],{"type":58,"value":64},"Enable Partial Prefetching and walk the app until every link reuses a shared App Shell. This skill sequences the work; per-insight recipes live in the dev overlay fix cards and their docs pages. The ",{"type":53,"tag":66,"props":67,"children":71},"a",{"href":68,"rel":69},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching",[70],"nofollow",[72],{"type":58,"value":73},"Adopting Partial Prefetching guide",{"type":58,"value":75}," is the canonical reference for the concepts this skill applies.",{"type":53,"tag":60,"props":77,"children":78},{},[79,81,96,98,104],{"type":58,"value":80},"The one thing that shapes everything below: ",{"type":53,"tag":82,"props":83,"children":84},"strong",{},[85,87,94],{"type":58,"value":86},"these insights surface only in ",{"type":53,"tag":88,"props":89,"children":91},"code",{"className":90},[],[92],{"type":58,"value":93},"next dev",{"type":58,"value":95},", in the dev overlay's Insights tab.",{"type":58,"value":97}," Nothing fails the build. There is no build-only fallback loop — confirming an insight is ",{"type":53,"tag":99,"props":100,"children":101},"em",{},[102],{"type":58,"value":103},"cleared",{"type":58,"value":105}," means driving the running app in a browser. But a missing browser gates that verification, not the whole skill: the adoption work is static and runs from the guide, so do the static pass anyway and hand off the live shell check.",{"type":53,"tag":60,"props":107,"children":108},{},[109,111,117,119,125],{"type":58,"value":110},"Talk to the user in terms of what they'll see — PRs, features, and how the app behaves after — never the insight slugs or step labels. Before you start, tell them briefly what Partial Prefetching changes: a ",{"type":53,"tag":88,"props":112,"children":114},{"className":113},[],[115],{"type":58,"value":116},"\u003CLink>",{"type":58,"value":118}," loads a shared App Shell, and ",{"type":53,"tag":88,"props":120,"children":122},{"className":121},[],[123],{"type":58,"value":124},"prefetch={true}",{"type":58,"value":126}," no longer prefetches everything the old full prefetch did.",{"type":53,"tag":128,"props":129,"children":131},"h2",{"id":130},"requires",[132],{"type":58,"value":130},{"type":53,"tag":134,"props":135,"children":136},"ul",{},[137,217,242,289],{"type":53,"tag":138,"props":139,"children":140},"li",{},[141,154,156,162,164,170,172,178,180,186,188,194,196,202,204,215],{"type":53,"tag":82,"props":142,"children":143},{},[144,146,152],{"type":58,"value":145},"Cache Components on (",{"type":53,"tag":88,"props":147,"children":149},{"className":148},[],[150],{"type":58,"value":151},"cacheComponents: true",{"type":58,"value":153},").",{"type":58,"value":155}," This is the only hard requirement; ",{"type":53,"tag":88,"props":157,"children":159},{"className":158},[],[160],{"type":58,"value":161},"partialPrefetching",{"type":58,"value":163}," depends on it. Full Cache Components adoption is the ideal starting point but not a gate. Nothing in this skill blocks the build, and neither do the prerender insights an unadopted route surfaces, like a leftover ",{"type":53,"tag":88,"props":165,"children":167},{"className":166},[],[168],{"type":58,"value":169},"unstable_noStore",{"type":58,"value":171}," or a ",{"type":53,"tag":88,"props":173,"children":175},{"className":174},[],[176],{"type":58,"value":177},"cookies()",{"type":58,"value":179}," read outside ",{"type":53,"tag":88,"props":181,"children":183},{"className":182},[],[184],{"type":58,"value":185},"\u003CSuspense>",{"type":58,"value":187},": they are non-blocking dev signals, expected on any fresh branch off ",{"type":53,"tag":88,"props":189,"children":191},{"className":190},[],[192],{"type":58,"value":193},"main",{"type":58,"value":195},", not a reason to stop. They replace the URL-data insight only on their own route in the ",{"type":53,"tag":66,"props":197,"children":199},{"href":198},"#step-3-sweep-for-url-data-insights-after-enabling",[200],{"type":58,"value":201},"step 3",{"type":58,"value":203}," sweep; the flag-off step 1 audit and its static adoption run regardless. The only thing that actually stops this skill is a build-blocking failure, and anything build-blocking would have been resolved before you reached here. Otherwise fix the prerender insights you hit as inline ",{"type":53,"tag":66,"props":205,"children":208},{"href":206,"rel":207},"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-cache-components-adoption",[70],[209],{"type":53,"tag":88,"props":210,"children":212},{"className":211},[],[213],{"type":58,"value":214},"next-cache-components-adoption",{"type":58,"value":216}," work, or hand them off, and keep going.",{"type":53,"tag":138,"props":218,"children":219},{},[220,225,227,232,234,240],{"type":53,"tag":82,"props":221,"children":222},{},[223],{"type":58,"value":224},"Next.js 16.3 or later.",{"type":58,"value":226}," ",{"type":53,"tag":88,"props":228,"children":230},{"className":229},[],[231],{"type":58,"value":161},{"type":58,"value":233},", the ",{"type":53,"tag":88,"props":235,"children":237},{"className":236},[],[238],{"type":58,"value":239},"prefetch",{"type":58,"value":241}," route segment config, and the prefetch insights all land there.",{"type":53,"tag":138,"props":243,"children":244},{},[245,250,252,263,265,271,273,279,281,287],{"type":53,"tag":82,"props":246,"children":247},{},[248],{"type":58,"value":249},"A browser you can drive.",{"type":58,"value":251}," Install ",{"type":53,"tag":66,"props":253,"children":256},{"href":254,"rel":255},"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-dev-loop",[70],[257],{"type":53,"tag":88,"props":258,"children":260},{"className":259},[],[261],{"type":58,"value":262},"next-dev-loop",{"type":58,"value":264}," before starting (",{"type":53,"tag":88,"props":266,"children":268},{"className":267},[],[269],{"type":58,"value":270},"npx skills add https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-dev-loop",{"type":58,"value":272},"). Install it without asking — it's a tool, not a product change — and don't assume it's blocked: verify a real blocker (no network, no npm, read-only filesystem) before falling back, and name it in your report. Link prefetches fire when a link renders and enters the viewport, and shell validation fires on navigation — neither is reachable from ",{"type":53,"tag":88,"props":274,"children":276},{"className":275},[],[277],{"type":58,"value":278},"curl",{"type":58,"value":280}," or the build. If the app is webpack-pinned, drive a browser directly (",{"type":53,"tag":88,"props":282,"children":284},{"className":283},[],[285],{"type":58,"value":286},"agent-browser",{"type":58,"value":288},", Playwright) — you lose the framework cross-checks, not the insights; they're still in the overlay and the dev log.",{"type":53,"tag":138,"props":290,"children":291},{},[292,297,299,304,306,312,314,320,322,328,330,336],{"type":53,"tag":82,"props":293,"children":294},{},[295],{"type":58,"value":296},"A runnable app.",{"type":58,"value":298}," Verification runs against ",{"type":53,"tag":88,"props":300,"children":302},{"className":301},[],[303],{"type":58,"value":93},{"type":58,"value":305}," for the insight sweep and a production ",{"type":53,"tag":88,"props":307,"children":309},{"className":308},[],[310],{"type":58,"value":311},"next build",{"type":58,"value":313},"\u002F",{"type":53,"tag":88,"props":315,"children":317},{"className":316},[],[318],{"type":58,"value":319},"next start",{"type":58,"value":321}," for prefetching (prefetching is prod-only), so the app has to boot in both. If it reads a database or required env at import (e.g. an ",{"type":53,"tag":88,"props":323,"children":325},{"className":324},[],[326],{"type":58,"value":327},"env.ts",{"type":58,"value":329}," that throws on a missing ",{"type":53,"tag":88,"props":331,"children":333},{"className":332},[],[334],{"type":58,"value":335},"DATABASE_URL",{"type":58,"value":337},"), confirm it starts — with the real environment, or local data you stand up — before step 1. An app that won't run can't be swept or verified.",{"type":53,"tag":339,"props":340,"children":342},"h3",{"id":341},"notes",[343],{"type":58,"value":341},{"type":53,"tag":134,"props":345,"children":346},{},[347,389],{"type":53,"tag":138,"props":348,"children":349},{},[350,355,357,363,365,371,373,379,381,387],{"type":53,"tag":82,"props":351,"children":352},{},[353],{"type":58,"value":354},"Offline docs.",{"type":58,"value":356}," Guide links have offline copies under ",{"type":53,"tag":88,"props":358,"children":360},{"className":359},[],[361],{"type":58,"value":362},"node_modules\u002Fnext\u002Fdist\u002Fdocs\u002F",{"type":58,"value":364}," (bundled since Next.js 16.2), with the directory layout numbered for ordering (e.g. ",{"type":53,"tag":88,"props":366,"children":368},{"className":367},[],[369],{"type":58,"value":370},"node_modules\u002Fnext\u002Fdist\u002Fdocs\u002F01-app\u002F02-guides\u002Fadopting-partial-prefetching.md",{"type":58,"value":372},"). If you can't predict the numbered prefix, ",{"type":53,"tag":88,"props":374,"children":376},{"className":375},[],[377],{"type":58,"value":378},"find node_modules\u002Fnext\u002Fdist\u002Fdocs -name '\u003Cslug>.md'",{"type":58,"value":380}," resolves it. The ",{"type":53,"tag":88,"props":382,"children":384},{"className":383},[],[385],{"type":58,"value":386},"\u002Fdocs\u002Fmessages\u002F*",{"type":58,"value":388}," error pages are not bundled.",{"type":53,"tag":138,"props":390,"children":391},{},[392,397,399,405,407,413,415,421,423,429],{"type":53,"tag":82,"props":393,"children":394},{},[395],{"type":58,"value":396},"Older versions without bundled docs.",{"type":58,"value":398}," Suggest ",{"type":53,"tag":88,"props":400,"children":402},{"className":401},[],[403],{"type":58,"value":404},"npx @next\u002Fcodemod@latest agents-md",{"type":58,"value":406}," to the user before starting: it downloads a version-matched copy to ",{"type":53,"tag":88,"props":408,"children":410},{"className":409},[],[411],{"type":58,"value":412},".next-docs\u002F",{"type":58,"value":414}," and writes an index into ",{"type":53,"tag":88,"props":416,"children":418},{"className":417},[],[419],{"type":58,"value":420},"AGENTS.md",{"type":58,"value":422}," \u002F ",{"type":53,"tag":88,"props":424,"children":426},{"className":425},[],[427],{"type":58,"value":428},"CLAUDE.md",{"type":58,"value":430},". It touches files in their repo, so ask first and run it only if they want it.",{"type":53,"tag":128,"props":432,"children":434},{"id":433},"background",[435],{"type":58,"value":433},{"type":53,"tag":60,"props":437,"children":438},{},[439,441,447],{"type":58,"value":440},"Adopting Partial Prefetching means every route still delivers what its links prefetched before, now split between the shared App Shell and any extra per-link data a link explicitly asks for. The ",{"type":53,"tag":66,"props":442,"children":444},{"href":68,"rel":443},[70],[445],{"type":58,"value":446},"guide",{"type":58,"value":448}," is the canonical reference for what a prefetch contains and how to decide each case; this skill sequences that work against a running app.",{"type":53,"tag":60,"props":450,"children":451},{},[452,454,460,462,468,470,481,483,490],{"type":58,"value":453},"The catch that decides most of the sweep: a default link warms only the shared App Shell. A route keyed by ",{"type":53,"tag":88,"props":455,"children":457},{"className":456},[],[458],{"type":58,"value":459},"params",{"type":58,"value":461}," or ",{"type":53,"tag":88,"props":463,"children":465},{"className":464},[],[466],{"type":58,"value":467},"searchParams",{"type":58,"value":469}," can prefetch more only after it has adopted Partial Prefetching and a specific link uses ",{"type":53,"tag":66,"props":471,"children":474},{"href":472,"rel":473},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fcomponents\u002Flink#prefetch",[70],[475],{"type":53,"tag":88,"props":476,"children":478},{"className":477},[],[479],{"type":58,"value":480},"\u003CLink prefetch={true}>",{"type":58,"value":482},"; then Next.js resolves the URL data and any cached content behind it before the click (the guide's ",{"type":53,"tag":66,"props":484,"children":487},{"href":485,"rel":486},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching#url-data",[70],[488],{"type":58,"value":489},"URL data",{"type":58,"value":491}," section).",{"type":53,"tag":128,"props":493,"children":495},{"id":494},"working-surfaces",[496],{"type":58,"value":497},"working surfaces",{"type":53,"tag":134,"props":499,"children":500},{},[501,527,553],{"type":53,"tag":138,"props":502,"children":503},{},[504,509,511,517,519,525],{"type":53,"tag":82,"props":505,"children":506},{},[507],{"type":58,"value":508},"The dev server terminal — your primary record.",{"type":58,"value":510}," Each validated route's insights are logged as ",{"type":53,"tag":88,"props":512,"children":514},{"className":513},[],[515],{"type":58,"value":516},"Error: Route \"...\": Next.js encountered ...",{"type":58,"value":518}," lines with the ",{"type":53,"tag":88,"props":520,"children":522},{"className":521},[],[523],{"type":58,"value":524},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002F\u003Cslug>",{"type":58,"value":526}," link. Tail the dev log during the sweep; it's the greppable record of what fired where, and it works the same on Turbopack and webpack.",{"type":53,"tag":138,"props":528,"children":529},{},[530,535,537,543,545,551],{"type":53,"tag":82,"props":531,"children":532},{},[533],{"type":58,"value":534},"The dev overlay Insights tab.",{"type":58,"value":536}," Insights are the amber, non-blocking tab. It appears only once an insight has fired, so a route that surfaces nothing shows no tab at all — that's the clean state, not a missing feature. Don't hunt for the tab on a quiet route; confirm clean from the dev log above, which is the reliable signal. The precondition is no blocking-prerender errors — those replace the insight on their route (see requires). An unrelated Issue (a hydration error, a console error) doesn't block the sweep; don't stall on it. When the tab is present, the overlay pill shows the count and each insight has fix cards linking its docs page. The overlay renders inside a shadow root (",{"type":53,"tag":88,"props":538,"children":540},{"className":539},[],[541],{"type":58,"value":542},"nextjs-portal",{"type":58,"value":544},"), so accessibility-tree snapshots don't see it — evaluate into ",{"type":53,"tag":88,"props":546,"children":548},{"className":547},[],[549],{"type":58,"value":550},"shadowRoot",{"type":58,"value":552}," when you need to read or click it programmatically.",{"type":53,"tag":138,"props":554,"children":555},{},[556,564,566,572,574,580,582,588,590,596],{"type":53,"tag":82,"props":557,"children":558},{},[559],{"type":53,"tag":88,"props":560,"children":562},{"className":561},[],[563],{"type":58,"value":262},{"type":58,"value":565}," to drive navigations and read the overlay. Prefer it over hand-rolled browser automation for the same reasons as in the Cache Components skill (webpack apps: see requires). When browsing its ",{"type":53,"tag":88,"props":567,"children":569},{"className":568},[],[570],{"type":58,"value":571},"\u002F_next\u002Fmcp",{"type":58,"value":573}," tools, the prefetch insights surface through ",{"type":53,"tag":88,"props":575,"children":577},{"className":576},[],[578],{"type":58,"value":579},"get_errors",{"type":58,"value":581}," and the overlay, not the similarly-named ",{"type":53,"tag":88,"props":583,"children":585},{"className":584},[],[586],{"type":58,"value":587},"get_request_insights",{"type":58,"value":589},". That one is the span and performance recorder (gated behind ",{"type":53,"tag":88,"props":591,"children":593},{"className":592},[],[594],{"type":58,"value":595},"experimental.requestInsights",{"type":58,"value":597},") and reports nothing about prefetching.",{"type":53,"tag":60,"props":599,"children":600},{},[601],{"type":58,"value":602},"Every insight has a docs page — open it. Fetch the linked page for every distinct insight you encounter; the inline message is a summary, the page is the recipe.",{"type":53,"tag":128,"props":604,"children":606},{"id":605},"step-1-audit-link-prefetchtrue-before-enabling",[607,609,614],{"type":58,"value":608},"step 1: audit ",{"type":53,"tag":88,"props":610,"children":612},{"className":611},[],[613],{"type":58,"value":480},{"type":58,"value":615}," (before enabling)",{"type":53,"tag":60,"props":617,"children":618},{},[619,621,627,629,635,637,641,643,648,650,656,658,669],{"type":58,"value":620},"If ",{"type":53,"tag":88,"props":622,"children":624},{"className":623},[],[625],{"type":58,"value":626},"partialPrefetching: true",{"type":58,"value":628}," is already set in ",{"type":53,"tag":88,"props":630,"children":632},{"className":631},[],[633],{"type":58,"value":634},"next.config.ts",{"type":58,"value":636},", the app is adopted — skip to ",{"type":53,"tag":66,"props":638,"children":639},{"href":198},[640],{"type":58,"value":201},{"type":58,"value":642},". Otherwise work the audit with the global flag ",{"type":53,"tag":82,"props":644,"children":645},{},[646],{"type":58,"value":647},"off",{"type":58,"value":649},", adopting each destination with ",{"type":53,"tag":88,"props":651,"children":653},{"className":652},[],[654],{"type":58,"value":655},"export const prefetch = 'partial'",{"type":58,"value":657}," — enabling the flag first would mark every route adopted and silence the ",{"type":53,"tag":66,"props":659,"children":662},{"href":660,"rel":661},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Finstant-link-prefetch-partial",[70],[663],{"type":53,"tag":88,"props":664,"children":666},{"className":665},[],[667],{"type":58,"value":668},"link-prefetch-partial",{"type":58,"value":670}," insight this audit runs on. Ask the user how to ship it, in the language of PRs:",{"type":53,"tag":134,"props":672,"children":673},{},[674,684],{"type":53,"tag":138,"props":675,"children":676},{},[677,682],{"type":53,"tag":82,"props":678,"children":679},{},[680],{"type":58,"value":681},"One branch",{"type":58,"value":683}," — the whole audit in one change, with the flag enabled and the codemod run at the end (step 2).",{"type":53,"tag":138,"props":685,"children":686},{},[687,692],{"type":53,"tag":82,"props":688,"children":689},{},[690],{"type":58,"value":691},"Route by route",{"type":58,"value":693}," — each adopted destination ships as its own PR. The insight still fires for the destinations you haven't reached, a live worklist, and step 2 comes after the last one.",{"type":53,"tag":60,"props":695,"children":696},{},[697],{"type":58,"value":698},"The work is identical either way — only the commit boundaries differ. Default by app size: one branch for a handful of links, route by route when the audit is big enough that reviewers need smaller diffs. Note the choice in your report.",{"type":53,"tag":60,"props":700,"children":701},{},[702,704,710,712,718,720,726,728,733,735,741,743,749,751,762,764,774,776,786,788,794,796,802],{"type":58,"value":703},"Enumerate the prefetch sites across the whole source tree, not only ",{"type":53,"tag":88,"props":705,"children":707},{"className":706},[],[708],{"type":58,"value":709},"app\u002F",{"type":58,"value":711}," — they often live in ",{"type":53,"tag":88,"props":713,"children":715},{"className":714},[],[716],{"type":58,"value":717},"src\u002Fcomponents",{"type":58,"value":719}," or shared UI packages: ",{"type":53,"tag":88,"props":721,"children":723},{"className":722},[],[724],{"type":58,"value":725},"rg -n '\\bprefetch\\b|router\\.prefetch' -g '*.tsx' -g '*.jsx' .",{"type":58,"value":727},". Keep the ",{"type":53,"tag":88,"props":729,"children":731},{"className":730},[],[732],{"type":58,"value":480},{"type":58,"value":734}," and bare-prop matches (a bare prop is ",{"type":53,"tag":88,"props":736,"children":738},{"className":737},[],[739],{"type":58,"value":740},"true",{"type":58,"value":742},") as the over-prefetching links this audit adopts destinations for, and drop ",{"type":53,"tag":88,"props":744,"children":746},{"className":745},[],[747],{"type":58,"value":748},"prefetch={false}",{"type":58,"value":750}," and other values. Also audit existing imperative ",{"type":53,"tag":66,"props":752,"children":755},{"href":753,"rel":754},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Ffunctions\u002Fuse-router#userouter",[70],[756],{"type":53,"tag":88,"props":757,"children":759},{"className":758},[],[760],{"type":58,"value":761},"router.prefetch()",{"type":58,"value":763}," call sites with the same table, because they can be preserving the same \"fetch before navigation\" behavior and have no dev insight. For new navigation prefetching, prefer ",{"type":53,"tag":66,"props":765,"children":768},{"href":766,"rel":767},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fcomponents\u002Flink",[70],[769],{"type":53,"tag":88,"props":770,"children":772},{"className":771},[],[773],{"type":58,"value":116},{"type":58,"value":775},", which the docs call the primary navigation API; use ",{"type":53,"tag":66,"props":777,"children":780},{"href":778,"rel":779},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fprefetching#manual-prefetch",[70],[781],{"type":53,"tag":88,"props":782,"children":784},{"className":783},[],[785],{"type":58,"value":761},{"type":58,"value":787}," only for manual prefetching. If the app already passes an internal ",{"type":53,"tag":88,"props":789,"children":791},{"className":790},[],[792],{"type":58,"value":793},"kind",{"type":58,"value":795}," option, treat that as existing implementation detail, not a pattern to spread. If nothing matches, check for a custom link wrapper before calling the audit empty. If there's still nothing, say so in your report and move on to ",{"type":53,"tag":66,"props":797,"children":799},{"href":798},"#step-2-enable-the-flag",[800],{"type":58,"value":801},"step 2",{"type":58,"value":803},".",{"type":53,"tag":60,"props":805,"children":806},{},[807],{"type":58,"value":808},"Then, for each one:",{"type":53,"tag":810,"props":811,"children":812},"ol",{},[813,869,987],{"type":53,"tag":138,"props":814,"children":815},{},[816,834,836,841,843,848,850,856,858,867],{"type":53,"tag":82,"props":817,"children":818},{},[819,821,826,828,833],{"type":58,"value":820},"Click each ",{"type":53,"tag":88,"props":822,"children":824},{"className":823},[],[825],{"type":58,"value":116},{"type":58,"value":827}," in ",{"type":53,"tag":88,"props":829,"children":831},{"className":830},[],[832],{"type":58,"value":93},{"type":58,"value":803},{"type":58,"value":835}," The insight fires at navigation time, not when the link prefetches, so a link sitting in the viewport won't trip it — you have to navigate through it. This click is ",{"type":53,"tag":99,"props":837,"children":838},{},[839],{"type":58,"value":840},"verification",{"type":58,"value":842},": it confirms the insight fires before you adopt and clears after. Imperative ",{"type":53,"tag":88,"props":844,"children":846},{"className":845},[],[847],{"type":58,"value":761},{"type":58,"value":849}," sites have no equivalent insight, so audit them from source and verify them in production (",{"type":53,"tag":66,"props":851,"children":853},{"href":852},"#step-4-verify",[854],{"type":58,"value":855},"step 4",{"type":58,"value":857},"). Without a browser, skip the click and adopt from ",{"type":53,"tag":66,"props":859,"children":861},{"href":660,"rel":860},[70],[862],{"type":53,"tag":88,"props":863,"children":865},{"className":864},[],[866],{"type":58,"value":668},{"type":58,"value":868}," and the audit table below — the destination's structure tells you the row, and type-check gates the edit — then leave the live confirmation for the hand-off.",{"type":53,"tag":138,"props":870,"children":871},{},[872,877,879,884,886,891,893,898,900,905,907,912,914,981,985],{"type":53,"tag":82,"props":873,"children":874},{},[875],{"type":58,"value":876},"Adopt the destination.",{"type":58,"value":878}," Add ",{"type":53,"tag":88,"props":880,"children":882},{"className":881},[],[883],{"type":58,"value":655},{"type":58,"value":885},". That clears the insight for every link pointing at it. If the route reads URL data (",{"type":53,"tag":88,"props":887,"children":889},{"className":888},[],[890],{"type":58,"value":459},{"type":58,"value":892},", ",{"type":53,"tag":88,"props":894,"children":896},{"className":895},[],[897],{"type":58,"value":467},{"type":58,"value":899},"), the default link still warms only its skeleton (the guide's ",{"type":53,"tag":66,"props":901,"children":903},{"href":485,"rel":902},[70],[904],{"type":58,"value":489},{"type":58,"value":906}," section), so it's a runtime-prefetch candidate for step 5, not a finished adoption. Keep ",{"type":53,"tag":88,"props":908,"children":910},{"className":909},[],[911],{"type":58,"value":124},{"type":58,"value":913}," on its links and mark the route:",{"type":53,"tag":915,"props":916,"children":921},"pre",{"className":917,"code":918,"language":919,"meta":920,"style":920},"language-tsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F TODO(runtime-prefetch): assess with the user whether URL data should resolve before click.\nexport const prefetch = 'partial'\n","tsx","",[922],{"type":53,"tag":88,"props":923,"children":924},{"__ignoreMap":920},[925,937],{"type":53,"tag":926,"props":927,"children":930},"span",{"class":928,"line":929},"line",1,[931],{"type":53,"tag":926,"props":932,"children":934},{"style":933},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic",[935],{"type":58,"value":936},"\u002F\u002F TODO(runtime-prefetch): assess with the user whether URL data should resolve before click.\n",{"type":53,"tag":926,"props":938,"children":940},{"class":928,"line":939},2,[941,947,953,959,965,970,976],{"type":53,"tag":926,"props":942,"children":944},{"style":943},"--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic",[945],{"type":58,"value":946},"export",{"type":53,"tag":926,"props":948,"children":950},{"style":949},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[951],{"type":58,"value":952}," const",{"type":53,"tag":926,"props":954,"children":956},{"style":955},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[957],{"type":58,"value":958}," prefetch ",{"type":53,"tag":926,"props":960,"children":962},{"style":961},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[963],{"type":58,"value":964},"=",{"type":53,"tag":926,"props":966,"children":967},{"style":961},[968],{"type":58,"value":969}," '",{"type":53,"tag":926,"props":971,"children":973},{"style":972},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[974],{"type":58,"value":975},"partial",{"type":53,"tag":926,"props":977,"children":978},{"style":961},[979],{"type":58,"value":980},"'\n",{"type":53,"tag":982,"props":983,"children":984},"br",{},[],{"type":58,"value":986},"Use that exact prefix so step 5 can grep them back. Don't cache or decide anything for these routes now.",{"type":53,"tag":138,"props":988,"children":989},{},[990,995,997,1004,1006,1017],{"type":53,"tag":82,"props":991,"children":992},{},[993],{"type":58,"value":994},"Preserve what that prefetch delivered.",{"type":58,"value":996}," The guide's ",{"type":53,"tag":66,"props":998,"children":1001},{"href":999,"rel":1000},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fadopting-partial-prefetching#auditing-link-prefetchtrue-calls",[70],[1002],{"type":58,"value":1003},"audit table",{"type":58,"value":1005}," is the canonical decision — fetch it and apply the matching row rather than re-deriving it. Caching uncached content is the judgment call in that table: trace where the data comes from and what freshness and revalidation it needs, per the ",{"type":53,"tag":66,"props":1007,"children":1010},{"href":1008,"rel":1009},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Fdirectives\u002Fuse-cache",[70],[1011],{"type":53,"tag":88,"props":1012,"children":1014},{"className":1013},[],[1015],{"type":58,"value":1016},"use cache",{"type":58,"value":1018}," docs, and ask the user when the answer isn't clear-cut. The URL-data routes you marked in the previous item wait for step 5.",{"type":53,"tag":1020,"props":1021,"children":1022},"blockquote",{},[1023],{"type":53,"tag":60,"props":1024,"children":1025},{},[1026,1045,1047,1052,1053,1059,1061,1066,1068,1077],{"type":53,"tag":82,"props":1027,"children":1028},{},[1029,1031,1036,1038,1043],{"type":58,"value":1030},"If you add ",{"type":53,"tag":88,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":58,"value":1016},{"type":58,"value":1037},", verify under ",{"type":53,"tag":88,"props":1039,"children":1041},{"className":1040},[],[1042],{"type":58,"value":319},{"type":58,"value":1044},", not only the build.",{"type":58,"value":1046}," A ",{"type":53,"tag":88,"props":1048,"children":1050},{"className":1049},[],[1051],{"type":58,"value":177},{"type":58,"value":313},{"type":53,"tag":88,"props":1054,"children":1056},{"className":1055},[],[1057],{"type":58,"value":1058},"headers()",{"type":58,"value":1060},"\u002Fsession read anywhere in the cached call tree throws at request time while ",{"type":53,"tag":88,"props":1062,"children":1064},{"className":1063},[],[1065],{"type":58,"value":311},{"type":58,"value":1067}," passes clean. See ",{"type":53,"tag":66,"props":1069,"children":1071},{"href":1008,"rel":1070},[70],[1072],{"type":53,"tag":88,"props":1073,"children":1075},{"className":1074},[],[1076],{"type":58,"value":1016},{"type":58,"value":803},{"type":53,"tag":128,"props":1079,"children":1081},{"id":1080},"step-2-enable-the-flag",[1082],{"type":58,"value":1083},"step 2: enable the flag",{"type":53,"tag":60,"props":1085,"children":1086},{},[1087,1089,1095],{"type":58,"value":1088},"Once every audited destination has ",{"type":53,"tag":88,"props":1090,"children":1092},{"className":1091},[],[1093],{"type":58,"value":1094},"prefetch = 'partial'",{"type":58,"value":1096},", finish in two moves.",{"type":53,"tag":810,"props":1098,"children":1099},{},[1100,1130],{"type":53,"tag":138,"props":1101,"children":1102},{},[1103,1108,1110,1115,1116,1121,1123,1128],{"type":53,"tag":82,"props":1104,"children":1105},{},[1106],{"type":58,"value":1107},"Enable the flag globally.",{"type":58,"value":1109}," Set ",{"type":53,"tag":88,"props":1111,"children":1113},{"className":1112},[],[1114],{"type":58,"value":626},{"type":58,"value":827},{"type":53,"tag":88,"props":1117,"children":1119},{"className":1118},[],[1120],{"type":58,"value":634},{"type":58,"value":1122}," (alongside ",{"type":53,"tag":88,"props":1124,"children":1126},{"className":1125},[],[1127],{"type":58,"value":151},{"type":58,"value":1129},"). Every route is adopted now, so every link is good.",{"type":53,"tag":138,"props":1131,"children":1132},{},[1133,1145,1147,1153,1155,1160,1162,1168,1170,1176,1178,1181,1183,1189,1191,1197,1199,1204,1206,1212,1214,1220,1222,1228,1229,1262,1265,1267,1273,1275,1280,1282,1287,1289,1295,1297,1302,1304,1309],{"type":53,"tag":82,"props":1134,"children":1135},{},[1136,1138,1143],{"type":58,"value":1137},"Strip the redundant ",{"type":53,"tag":88,"props":1139,"children":1141},{"className":1140},[],[1142],{"type":58,"value":1094},{"type":58,"value":1144}," exports.",{"type":58,"value":1146}," Run the first-party ",{"type":53,"tag":88,"props":1148,"children":1150},{"className":1149},[],[1151],{"type":58,"value":1152},"remove-partial-prefetch",{"type":58,"value":1154}," codemod rather than a text find-and-replace. It removes only ",{"type":53,"tag":88,"props":1156,"children":1158},{"className":1157},[],[1159],{"type":58,"value":655},{"type":58,"value":1161}," and leaves other values such as ",{"type":53,"tag":88,"props":1163,"children":1165},{"className":1164},[],[1166],{"type":58,"value":1167},"prefetch = 'force-disabled'",{"type":58,"value":1169}," in place, along with your ",{"type":53,"tag":88,"props":1171,"children":1173},{"className":1172},[],[1174],{"type":58,"value":1175},"TODO(runtime-prefetch)",{"type":58,"value":1177}," markers, which wait for step 5.",{"type":53,"tag":982,"props":1179,"children":1180},{},[],{"type":58,"value":1182},"Use the ",{"type":53,"tag":88,"props":1184,"children":1186},{"className":1185},[],[1187],{"type":58,"value":1188},"@canary",{"type":58,"value":1190}," channel, not ",{"type":53,"tag":88,"props":1192,"children":1194},{"className":1193},[],[1195],{"type":58,"value":1196},"@latest",{"type":58,"value":1198},". The ",{"type":53,"tag":88,"props":1200,"children":1202},{"className":1201},[],[1203],{"type":58,"value":1152},{"type":58,"value":1205}," transform isn't in the stable ",{"type":53,"tag":88,"props":1207,"children":1209},{"className":1208},[],[1210],{"type":58,"value":1211},"@next\u002Fcodemod",{"type":58,"value":1213}," release yet, and ",{"type":53,"tag":88,"props":1215,"children":1217},{"className":1216},[],[1218],{"type":58,"value":1219},"@next\u002Fcodemod@latest",{"type":58,"value":1221}," errors with ",{"type":53,"tag":88,"props":1223,"children":1225},{"className":1224},[],[1226],{"type":58,"value":1227},"Invalid transform choice",{"type":58,"value":803},{"type":53,"tag":915,"props":1230,"children":1234},{"className":1231,"code":1232,"language":1233,"meta":920,"style":920},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","npx @next\u002Fcodemod@canary remove-partial-prefetch .\u002Fapp\n","bash",[1235],{"type":53,"tag":88,"props":1236,"children":1237},{"__ignoreMap":920},[1238],{"type":53,"tag":926,"props":1239,"children":1240},{"class":928,"line":929},[1241,1247,1252,1257],{"type":53,"tag":926,"props":1242,"children":1244},{"style":1243},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[1245],{"type":58,"value":1246},"npx",{"type":53,"tag":926,"props":1248,"children":1249},{"style":972},[1250],{"type":58,"value":1251}," @next\u002Fcodemod@canary",{"type":53,"tag":926,"props":1253,"children":1254},{"style":972},[1255],{"type":58,"value":1256}," remove-partial-prefetch",{"type":53,"tag":926,"props":1258,"children":1259},{"style":972},[1260],{"type":58,"value":1261}," .\u002Fapp\n",{"type":53,"tag":982,"props":1263,"children":1264},{},[],{"type":58,"value":1266},"The codemod refuses to run on a dirty working tree. Commit or stash unrelated work first, or pass ",{"type":53,"tag":88,"props":1268,"children":1270},{"className":1269},[],[1271],{"type":58,"value":1272},"--force",{"type":58,"value":1274}," to let its edits land alongside your WIP. If the codemod isn't available (older ",{"type":53,"tag":88,"props":1276,"children":1278},{"className":1277},[],[1279],{"type":58,"value":1211},{"type":58,"value":1281},", sandboxed environment, offline run), reproduce it by hand by removing ",{"type":53,"tag":88,"props":1283,"children":1285},{"className":1284},[],[1286],{"type":58,"value":655},{"type":58,"value":1288}," from every ",{"type":53,"tag":88,"props":1290,"children":1292},{"className":1291},[],[1293],{"type":58,"value":1294},"app\u002F**\u002F{page,layout}.{js,jsx,ts,tsx}",{"type":58,"value":1296}," — leave other ",{"type":53,"tag":88,"props":1298,"children":1300},{"className":1299},[],[1301],{"type":58,"value":239},{"type":58,"value":1303}," values in place, and leave the ",{"type":53,"tag":88,"props":1305,"children":1307},{"className":1306},[],[1308],{"type":58,"value":1175},{"type":58,"value":1310}," markers where they are. Don't hand-edit when the codemod can run.",{"type":53,"tag":128,"props":1312,"children":1314},{"id":1313},"step-3-sweep-for-url-data-insights-after-enabling",[1315],{"type":58,"value":1316},"step 3: sweep for URL-data insights (after enabling)",{"type":53,"tag":60,"props":1318,"children":1319},{},[1320,1322,1327,1329,1334],{"type":58,"value":1321},"This is a dev-only second pass. The shell check runs only with the flag on, fires at navigation time, and never blocks the build, so it can happen any time after step 2. Build the route queue from a concrete source (the last ",{"type":53,"tag":88,"props":1323,"children":1325},{"className":1324},[],[1326],{"type":58,"value":311},{"type":58,"value":1328}," route table, or the ",{"type":53,"tag":88,"props":1330,"children":1332},{"className":1331},[],[1333],{"type":58,"value":709},{"type":58,"value":1335}," tree) and keep it as a todo list.",{"type":53,"tag":60,"props":1337,"children":1338},{},[1339,1341,1347,1348,1354,1356,1361],{"type":58,"value":1340},"Sweep feature by feature. A feature is a single product surface — ",{"type":53,"tag":88,"props":1342,"children":1344},{"className":1343},[],[1345],{"type":58,"value":1346},"app\u002Fsettings\u002F**",{"type":58,"value":892},{"type":53,"tag":88,"props":1349,"children":1351},{"className":1350},[],[1352],{"type":58,"value":1353},"app\u002Fposts\u002F[slug]\u002F**",{"type":58,"value":1355}," — not a whole top-level area. Finish one end-to-end before starting the next: load its routes in ",{"type":53,"tag":88,"props":1357,"children":1359},{"className":1358},[],[1360],{"type":58,"value":93},{"type":58,"value":1362}," and resolve their insights. The insight never blocks the build and each route is independent, so a partial sweep leaves a working app, and each feature is a self-contained change the user can review or ship on its own.",{"type":53,"tag":60,"props":1364,"children":1365},{},[1366,1368,1378,1380,1385,1387,1392],{"type":58,"value":1367},"If the environment can't finish the whole sweep (slow first compiles, a dev server that falls over under load, no browser at all), take the browser-free work as far as it goes before handing off. Adopt every route you can statically: apply the fix from ",{"type":53,"tag":66,"props":1369,"children":1372},{"href":1370,"rel":1371},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Finstant-shell-url-data",[70],[1373],{"type":53,"tag":88,"props":1374,"children":1376},{"className":1375},[],[1377],{"type":58,"value":489},{"type":58,"value":1379}," (up to a new ",{"type":53,"tag":88,"props":1381,"children":1383},{"className":1382},[],[1384],{"type":58,"value":185},{"type":58,"value":1386}," boundary) and opt the route into ",{"type":53,"tag":88,"props":1388,"children":1390},{"className":1389},[],[1391],{"type":58,"value":1094},{"type":58,"value":1393},", gating on type-check. Work the whole queue in one pass — a larger refactor isn't a reason to defer, and asking whether to continue to the next route or tier isn't a checkpoint; keep going. Stop only for a genuine judgment call, and batch those into the single hand-off report: the routes you statically adopted, the ones still needing a live shell check, and the queue.",{"type":53,"tag":60,"props":1395,"children":1396},{},[1397,1399,1405,1407,1416,1418,1423,1424,1429,1431,1437,1439,1444,1446,1451,1453,1459],{"type":58,"value":1398},"Watch the Insights tab and the dev log for ",{"type":53,"tag":88,"props":1400,"children":1402},{"className":1401},[],[1403],{"type":58,"value":1404},"Next.js encountered … data",{"type":58,"value":1406}," lines. The signal this step adds is ",{"type":53,"tag":66,"props":1408,"children":1410},{"href":1370,"rel":1409},[70],[1411],{"type":53,"tag":88,"props":1412,"children":1414},{"className":1413},[],[1415],{"type":58,"value":489},{"type":58,"value":1417},": a ",{"type":53,"tag":88,"props":1419,"children":1421},{"className":1420},[],[1422],{"type":58,"value":459},{"type":58,"value":461},{"type":53,"tag":88,"props":1425,"children":1427},{"className":1426},[],[1428],{"type":58,"value":467},{"type":58,"value":1430}," read too high in the suspended subtree ties the shared shell to one URL. This insight is narrow; it most reliably appears on a ",{"type":53,"tag":88,"props":1432,"children":1434},{"className":1433},[],[1435],{"type":58,"value":1436},"generateStaticParams",{"type":58,"value":1438}," route where ",{"type":53,"tag":88,"props":1440,"children":1442},{"className":1441},[],[1443],{"type":58,"value":459},{"type":58,"value":1445}," is already under ",{"type":53,"tag":88,"props":1447,"children":1449},{"className":1448},[],[1450],{"type":58,"value":185},{"type":58,"value":1452},", but still awaited before the URL-specific leaf boundary. If a ",{"type":53,"tag":88,"props":1454,"children":1456},{"className":1455},[],[1457],{"type":58,"value":1458},"blocking-prerender-*",{"type":58,"value":1460}," error fires instead, apply the same structural fix.",{"type":53,"tag":60,"props":1462,"children":1463},{},[1464,1466,1472,1474,1479,1481,1492,1494,1499,1500,1505,1507,1518,1520,1526,1528,1534,1535,1541],{"type":58,"value":1465},"Loading a route with the flag on prerenders its App Shell, which validates more of the route than the Cache Components build did. So a route that built cleanly under Cache Components (every route ",{"type":53,"tag":88,"props":1467,"children":1469},{"className":1468},[],[1470],{"type":58,"value":1471},"◐",{"type":58,"value":1473},", no errors) can still surface a ",{"type":53,"tag":88,"props":1475,"children":1477},{"className":1476},[],[1478],{"type":58,"value":1458},{"type":58,"value":1480}," error here the first time its shell is prerendered — ",{"type":53,"tag":66,"props":1482,"children":1485},{"href":1483,"rel":1484},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Fblocking-prerender-runtime",[70],[1486],{"type":53,"tag":88,"props":1487,"children":1489},{"className":1488},[],[1490],{"type":58,"value":1491},"runtime data",{"type":58,"value":1493}," (",{"type":53,"tag":88,"props":1495,"children":1497},{"className":1496},[],[1498],{"type":58,"value":177},{"type":58,"value":313},{"type":53,"tag":88,"props":1501,"children":1503},{"className":1502},[],[1504],{"type":58,"value":1058},{"type":58,"value":1506},"), ",{"type":53,"tag":66,"props":1508,"children":1511},{"href":1509,"rel":1510},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002Fblocking-prerender-dynamic",[70],[1512],{"type":53,"tag":88,"props":1513,"children":1515},{"className":1514},[],[1516],{"type":58,"value":1517},"uncached data",{"type":58,"value":1519}," (an uncached ",{"type":53,"tag":88,"props":1521,"children":1523},{"className":1522},[],[1524],{"type":58,"value":1525},"fetch",{"type":58,"value":1527},"\u002FDB call), or sync IO like ",{"type":53,"tag":88,"props":1529,"children":1531},{"className":1530},[],[1532],{"type":58,"value":1533},"Date.now()",{"type":58,"value":313},{"type":53,"tag":88,"props":1536,"children":1538},{"className":1537},[],[1539],{"type":58,"value":1540},"new Date()",{"type":58,"value":1542},". This doesn't mean the Cache Components adoption was incomplete; it's new validation reaching a path the build never exercised. These aren't Partial Prefetching insights — fix each one the same way you would any blocking-prerender error.",{"type":53,"tag":60,"props":1544,"children":1545},{},[1546,1548,1553],{"type":58,"value":1547},"These fixes rarely involve the user — each insight names the offending read and its docs page has the fix, so apply it and keep sweeping. Collect the rare exceptions for one batched question at the end: a page that is entirely one URL-dependent region (wrapping it all leaves an empty shell), or a route that should arguably stay opted out. Don't narrate the refactor with comments — the ",{"type":53,"tag":88,"props":1549,"children":1551},{"className":1550},[],[1552],{"type":58,"value":185},{"type":58,"value":1554}," boundaries speak for themselves.",{"type":53,"tag":128,"props":1556,"children":1558},{"id":1557},"step-4-verify",[1559],{"type":58,"value":1560},"step 4: verify",{"type":53,"tag":60,"props":1562,"children":1563},{},[1564],{"type":58,"value":1565},"Checklist before checking in with the user:",{"type":53,"tag":134,"props":1567,"children":1568},{},[1569,1607,1619,1631,1669,1686],{"type":53,"tag":138,"props":1570,"children":1571},{},[1572,1577,1579,1584,1586,1591,1593,1598,1600,1605],{"type":53,"tag":82,"props":1573,"children":1574},{},[1575],{"type":58,"value":1576},"An empty sweep is expected when Cache Components adoption finished cleanly.",{"type":58,"value":1578}," A quiet log is success, not a missing signal. If you deliberately probe the validation path, use a ",{"type":53,"tag":88,"props":1580,"children":1582},{"className":1581},[],[1583],{"type":58,"value":1436},{"type":58,"value":1585}," route with ",{"type":53,"tag":88,"props":1587,"children":1589},{"className":1588},[],[1590],{"type":58,"value":459},{"type":58,"value":1592}," read inside ",{"type":53,"tag":88,"props":1594,"children":1596},{"className":1595},[],[1597],{"type":58,"value":185},{"type":58,"value":1599}," but before the URL-specific leaf boundary; other shapes may surface ",{"type":53,"tag":88,"props":1601,"children":1603},{"className":1602},[],[1604],{"type":58,"value":1458},{"type":58,"value":1606}," instead.",{"type":53,"tag":138,"props":1608,"children":1609},{},[1610,1612,1617],{"type":58,"value":1611},"The App Shells are real: for each route you changed, confirm the first paint after a navigation shows the intended shared content, not an empty shell or a stuck fallback. A ",{"type":53,"tag":88,"props":1613,"children":1615},{"className":1614},[],[1616],{"type":58,"value":185},{"type":58,"value":1618}," around the whole page body passes validation with an empty shell, which defeats the point.",{"type":53,"tag":138,"props":1620,"children":1621},{},[1622,1624,1629],{"type":58,"value":1623},"The insights validate shell ",{"type":53,"tag":99,"props":1625,"children":1626},{},[1627],{"type":58,"value":1628},"structure",{"type":58,"value":1630},", not that a prefetch actually happened. Confirm on the production run (prefetching is prod-only) that navigating a changed link lands on the shared shell instantly.",{"type":53,"tag":138,"props":1632,"children":1633},{},[1634,1639,1641,1646,1648,1654,1656,1661,1663,1668],{"type":53,"tag":82,"props":1635,"children":1636},{},[1637],{"type":58,"value":1638},"If the app prefetches imperatively",{"type":58,"value":1640},", the insight sweep does not cover it, so an empty sweep is not proof the prefetch survived the flag. Verify the call under ",{"type":53,"tag":88,"props":1642,"children":1644},{"className":1643},[],[1645],{"type":58,"value":319},{"type":58,"value":1647},": compare the ",{"type":53,"tag":88,"props":1649,"children":1651},{"className":1650},[],[1652],{"type":58,"value":1653},"_rsc",{"type":58,"value":1655}," prefetch response or resource timing before\u002Fafter, and make sure any intentionally preserved full prefetch still carries the data the old call was warming. If it now returns only the App Shell, migrate that call site using the same decision as the nearest ",{"type":53,"tag":88,"props":1657,"children":1659},{"className":1658},[],[1660],{"type":58,"value":480},{"type":58,"value":1662}," destination — cache the data, or move runtime-prefetch behavior to a docs-supported ",{"type":53,"tag":88,"props":1664,"children":1666},{"className":1665},[],[1667],{"type":58,"value":480},{"type":58,"value":803},{"type":53,"tag":138,"props":1670,"children":1671},{},[1672,1684],{"type":53,"tag":82,"props":1673,"children":1674},{},[1675,1677,1682],{"type":58,"value":1676},"Before blaming a broken route on the flag, reproduce it with ",{"type":53,"tag":88,"props":1678,"children":1680},{"className":1679},[],[1681],{"type":58,"value":161},{"type":58,"value":1683}," off",{"type":58,"value":1685}," (or on the pre-flag branch). The flag surfaces existing issues — a fragile request-time auth gate, a rewrite, deployment skew — earlier and more visibly, but rarely causes them. If it breaks flag-off too, it isn't a Partial Prefetching problem; fix it there, not here.",{"type":53,"tag":138,"props":1687,"children":1688},{},[1689,1694],{"type":53,"tag":88,"props":1690,"children":1692},{"className":1691},[],[1693],{"type":58,"value":311},{"type":58,"value":1695}," still passes.",{"type":53,"tag":60,"props":1697,"children":1698},{},[1699],{"type":58,"value":1700},"Then check in with the user. Speak their language — no insight slugs or step labels.",{"type":53,"tag":134,"props":1702,"children":1703},{},[1704,1709,1728,1754,1759,1764],{"type":53,"tag":138,"props":1705,"children":1706},{},[1707],{"type":58,"value":1708},"What you did: which links you audited, which destinations you adopted, and what each link now prefetches.",{"type":53,"tag":138,"props":1710,"children":1711},{},[1712,1714,1719,1721,1726],{"type":58,"value":1713},"What changed: dropped props, ",{"type":53,"tag":88,"props":1715,"children":1717},{"className":1716},[],[1718],{"type":58,"value":1016},{"type":58,"value":1720}," boundaries added, and which routes carry a ",{"type":53,"tag":88,"props":1722,"children":1724},{"className":1723},[],[1725],{"type":58,"value":1175},{"type":58,"value":1727}," marker for later.",{"type":53,"tag":138,"props":1729,"children":1730},{},[1731,1733,1738,1740,1745,1747,1752],{"type":58,"value":1732},"Demo against a production run. Prefetching is limited in development, so ",{"type":53,"tag":88,"props":1734,"children":1736},{"className":1735},[],[1737],{"type":58,"value":93},{"type":58,"value":1739}," won't show the result — run ",{"type":53,"tag":88,"props":1741,"children":1743},{"className":1742},[],[1744],{"type":58,"value":311},{"type":58,"value":1746}," and ",{"type":53,"tag":88,"props":1748,"children":1750},{"className":1749},[],[1751],{"type":58,"value":319},{"type":58,"value":1753},", and hand the user that URL. That run needs the app's real environment (database, auth, secrets), and a partial or stale install or leftover generated artifacts can fail the build for reasons unrelated to the adoption. Set the expectation up front that verification is a complete, credentialed production run, not a quick check.",{"type":53,"tag":138,"props":1755,"children":1756},{},[1757],{"type":58,"value":1758},"Show, don't tell: drive one link live in the headed browser against the production server, so they see the shared App Shell paint instantly and the URL-specific region stream in. Attach before\u002Fafter screenshots only when a live browser isn't possible.",{"type":53,"tag":138,"props":1760,"children":1761},{},[1762],{"type":58,"value":1763},"Give them the click-through: a table of each changed route — the link to click, and what to expect after the click (what paints instantly, what streams in) — so they can verify each result themselves.",{"type":53,"tag":138,"props":1765,"children":1766},{},[1767],{"type":58,"value":1768},"The question: \"Want to commit this (or open the PR) before we look at which routes should also prefetch their URL-specific content?\" Wait for the answer — adoption and runtime prefetching read best as their own changes.",{"type":53,"tag":128,"props":1770,"children":1772},{"id":1771},"step-5-runtime-prefetching-optional",[1773],{"type":58,"value":1774},"step 5: runtime prefetching (optional)",{"type":53,"tag":60,"props":1776,"children":1777},{},[1778,1780,1785,1787,1794],{"type":58,"value":1779},"The audit marked the candidates instead of deciding them. Grep for ",{"type":53,"tag":88,"props":1781,"children":1783},{"className":1782},[],[1784],{"type":58,"value":1175},{"type":58,"value":1786}," and walk the list with the user in one conversation. The question per route is whether they want the URL-dependent content prefetched ahead of the click, or streaming in after navigation is fine. A runtime prefetch costs a server invocation per prefetchable link — the guide's ",{"type":53,"tag":66,"props":1788,"children":1791},{"href":1789,"rel":1790},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fruntime-prefetching#per-link-prefetching-trade-offs",[70],[1792],{"type":58,"value":1793},"per-link prefetching trade-offs",{"type":58,"value":1795}," section is the checklist. Don't make these calls alone.",{"type":53,"tag":60,"props":1797,"children":1798},{},[1799,1801,1808,1810,1819,1821,1826,1828,1834,1836,1842,1844,1851,1853,1858,1860,1865,1866,1871,1873,1878],{"type":58,"value":1800},"Where the answer is yes, follow the ",{"type":53,"tag":66,"props":1802,"children":1805},{"href":1803,"rel":1804},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fruntime-prefetching",[70],[1806],{"type":58,"value":1807},"runtime prefetching guide",{"type":58,"value":1809},": keep ",{"type":53,"tag":66,"props":1811,"children":1813},{"href":472,"rel":1812},[70],[1814],{"type":53,"tag":88,"props":1815,"children":1817},{"className":1816},[],[1818],{"type":58,"value":480},{"type":58,"value":1820}," on the links that should resolve more than the App Shell, and cache the content behind the URL-data read using the guide's patterns (",{"type":53,"tag":88,"props":1822,"children":1824},{"className":1823},[],[1825],{"type":58,"value":1016},{"type":58,"value":1827}," with the runtime value passed in, or ",{"type":53,"tag":88,"props":1829,"children":1831},{"className":1830},[],[1832],{"type":58,"value":1833},"use cache: private",{"type":58,"value":1835}," for per-user data). Each per-link prefetch is a server render when the destination needs non-static data, so use the guide's ",{"type":53,"tag":66,"props":1837,"children":1839},{"href":1789,"rel":1838},[70],[1840],{"type":58,"value":1841},"per-link trade-offs",{"type":58,"value":1843}," to decide when viewport prefetching is worth it and when ",{"type":53,"tag":66,"props":1845,"children":1848},{"href":1846,"rel":1847},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fprefetching#hover-triggered-prefetch",[70],[1849],{"type":58,"value":1850},"hover-triggered prefetch",{"type":58,"value":1852}," is a better fit. Where it's no, delete the marker and leave the route on the App Shell default. Either way no ",{"type":53,"tag":88,"props":1854,"children":1856},{"className":1855},[],[1857],{"type":58,"value":1175},{"type":58,"value":1859}," marker survives this step. Confirm the opted-in links against a production run (",{"type":53,"tag":88,"props":1861,"children":1863},{"className":1862},[],[1864],{"type":58,"value":311},{"type":58,"value":1746},{"type":53,"tag":88,"props":1867,"children":1869},{"className":1868},[],[1870],{"type":58,"value":319},{"type":58,"value":1872}," — the runtime prefetch fires there, not in ",{"type":53,"tag":88,"props":1874,"children":1876},{"className":1875},[],[1877],{"type":58,"value":93},{"type":58,"value":1879},"), give the user the same click-through for them, and keep this as its own commit or PR.",{"type":53,"tag":128,"props":1881,"children":1883},{"id":1882},"further-reading",[1884],{"type":58,"value":1885},"further reading",{"type":53,"tag":134,"props":1887,"children":1888},{},[1889,1901,1928],{"type":53,"tag":138,"props":1890,"children":1891},{},[1892,1899],{"type":53,"tag":66,"props":1893,"children":1896},{"href":1894,"rel":1895},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Finstant-navigation",[70],[1897],{"type":58,"value":1898},"Instant navigation",{"type":58,"value":1900}," — the broader validation model and loading-state tooling.",{"type":53,"tag":138,"props":1902,"children":1903},{},[1904,1911,1913,1919,1920,1926],{"type":53,"tag":66,"props":1905,"children":1908},{"href":1906,"rel":1907},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Finstant-navigation#prevent-regressions-with-e2e-tests",[70],[1909],{"type":58,"value":1910},"Prevent regressions with e2e tests",{"type":58,"value":1912}," — the ",{"type":53,"tag":88,"props":1914,"children":1916},{"className":1915},[],[1917],{"type":58,"value":1918},"@next\u002Fplaywright",{"type":58,"value":226},{"type":53,"tag":88,"props":1921,"children":1923},{"className":1922},[],[1924],{"type":58,"value":1925},"instant()",{"type":58,"value":1927}," helper locks in what a navigation shows immediately; recommend it once the sweep is clean, since nothing else guards these in CI.",{"type":53,"tag":138,"props":1929,"children":1930},{},[1931,1942],{"type":53,"tag":66,"props":1932,"children":1935},{"href":1933,"rel":1934},"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-cache-components-optimizer",[70],[1936],{"type":53,"tag":88,"props":1937,"children":1939},{"className":1938},[],[1940],{"type":58,"value":1941},"next-cache-components-optimizer",{"type":58,"value":1943}," — grows each route's static shell so the App Shell carries more.",{"type":53,"tag":1945,"props":1946,"children":1947},"style",{},[1948],{"type":58,"value":1949},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1951,"total":2003},[1952,1967,1978,1996],{"slug":214,"name":214,"fn":1953,"description":1954,"org":1955,"tags":1956,"stars":23,"repoUrl":24,"updatedAt":1966},"enable and migrate to Next.js Cache Components","Turn on Cache Components in a Next.js app and resolve the blocking routes it surfaces. Use when the user wants to enable, adopt, or migrate to Cache Components, flip the `cacheComponents` flag, work through a flood of blocking-prerender \u002F instant validation errors, run the `cache-components-instant-false` codemod, or decide between opting routes out with `export const instant = false` and fixing them in place.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1957,1960,1961,1964,1965],{"name":1958,"slug":1959,"type":15},"Caching","caching",{"name":21,"slug":22,"type":15},{"name":1962,"slug":1963,"type":15},"Migration","migration",{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},"2026-07-24T05:38:30.118542",{"slug":1941,"name":1941,"fn":1968,"description":1969,"org":1970,"tags":1971,"stars":23,"repoUrl":24,"updatedAt":1977},"optimize Next.js cache components","Drive a Next.js route to instant navigation by setting up an agentic loop, under Cache Components \u002F PPR, on initial load (hard navigation) and client-side navigation (soft navigation). Encode the goal as a failing @next\u002Fplaywright instant() e2e and work it to green, one verified route at a time; the shipped test then guards against regression. Use when asked to make a route's navigation instant (its static shell commits immediately), fix a route whose static shell isn't prerendered\u002Fserved\u002Fprefetched, grow a route's static shell or fix its slow first paint, diagnose which Suspense boundary keeps a route out of its static shell, or write the instant() e2e guard for one. Requires Next.js 16.3+ with cacheComponents; directs an upgrade if older.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1972,1973,1974,1975,1976],{"name":1958,"slug":1959,"type":15},{"name":21,"slug":22,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-07-30T05:31:10.674078",{"slug":262,"name":262,"fn":1979,"description":1980,"org":1981,"tags":1982,"stars":23,"repoUrl":24,"updatedAt":1995},"verify Next.js runtime behavior","Verify Next.js runtime behavior after editing app code. Use this skill to confirm a change actually works in a running app — not just that it compiles or type-checks. Combines \u002F_next\u002Fmcp (Next.js's view) with agent-browser (the browser's view). Requires a running `next dev`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1983,1986,1987,1990,1991,1992],{"name":1984,"slug":1985,"type":15},"Debugging","debugging",{"name":21,"slug":22,"type":15},{"name":1988,"slug":1989,"type":15},"Local Development","local-development",{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":1993,"slug":1994,"type":15},"Web Development","web-development","2026-05-22T06:45:28.627735",{"slug":4,"name":4,"fn":5,"description":6,"org":1997,"tags":1998,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1999,2000,2001,2002],{"name":21,"slug":22,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},4,{"items":2005,"total":2150},[2006,2014,2022,2031,2038,2053,2069,2087,2099,2118,2130,2140],{"slug":214,"name":214,"fn":1953,"description":1954,"org":2007,"tags":2008,"stars":23,"repoUrl":24,"updatedAt":1966},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2009,2010,2011,2012,2013],{"name":1958,"slug":1959,"type":15},{"name":21,"slug":22,"type":15},{"name":1962,"slug":1963,"type":15},{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"slug":1941,"name":1941,"fn":1968,"description":1969,"org":2015,"tags":2016,"stars":23,"repoUrl":24,"updatedAt":1977},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2017,2018,2019,2020,2021],{"name":1958,"slug":1959,"type":15},{"name":21,"slug":22,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":262,"name":262,"fn":1979,"description":1980,"org":2023,"tags":2024,"stars":23,"repoUrl":24,"updatedAt":1995},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2025,2026,2027,2028,2029,2030],{"name":1984,"slug":1985,"type":15},{"name":21,"slug":22,"type":15},{"name":1988,"slug":1989,"type":15},{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":1993,"slug":1994,"type":15},{"slug":4,"name":4,"fn":5,"description":6,"org":2032,"tags":2033,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2034,2035,2036,2037],{"name":21,"slug":22,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":2039,"name":2039,"fn":2040,"description":2041,"org":2042,"tags":2043,"stars":2050,"repoUrl":2051,"updatedAt":2052},"turborepo","manage monorepos with Turborepo","Turborepo monorepo build system guidance. Triggers on: turbo.json, task pipelines,\ndependsOn, caching, remote cache, the \"turbo\" CLI, --filter, --affected, CI optimization, environment\nvariables, internal packages, monorepo structure\u002Fbest practices, and boundaries.\n\nUse when user: configures tasks\u002Fworkflows\u002Fpipelines, creates packages, sets up\nmonorepo, shares code between apps, runs changed\u002Faffected packages, debugs cache,\nor has apps\u002Fpackages directories.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2044,2047,2048],{"name":2045,"slug":2046,"type":15},"CI\u002FCD","ci-cd",{"name":13,"slug":14,"type":15},{"name":2049,"slug":2039,"type":15},"Turborepo",30809,"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fturborepo","2026-07-30T05:32:14.920116",{"slug":2054,"name":2054,"fn":2055,"description":2056,"org":2057,"tags":2058,"stars":2066,"repoUrl":2067,"updatedAt":2068},"add-function-examples","add AI function examples for testing","Guide for adding new AI function examples, for testing specific features against the actual provider APIs.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2059,2062,2065],{"name":2060,"slug":2061,"type":15},"AI SDK","ai-sdk",{"name":2063,"slug":2064,"type":15},"Testing","testing",{"name":9,"slug":8,"type":15},25670,"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fai","2026-04-06T18:55:51.318866",{"slug":2070,"name":2070,"fn":2071,"description":2072,"org":2073,"tags":2074,"stars":2066,"repoUrl":2067,"updatedAt":2086},"add-harness-package","add AI SDK harness packages","Guide for adding new AI SDK harness packages. Use when creating a new @ai-sdk\u002Fharness-\u003Cname> package that adapts a coding-agent runtime to HarnessV1.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2075,2078,2079,2082,2085],{"name":2076,"slug":2077,"type":15},"Agents","agents",{"name":2060,"slug":2061,"type":15},{"name":2080,"slug":2081,"type":15},"Harness","harness",{"name":2083,"slug":2084,"type":15},"SDK","sdk",{"name":9,"slug":8,"type":15},"2026-06-18T08:29:19.858737",{"slug":2088,"name":2088,"fn":2089,"description":2090,"org":2091,"tags":2092,"stars":2066,"repoUrl":2067,"updatedAt":2098},"add-provider-package","add new provider packages to AI SDK","Guide for adding new AI provider packages to the AI SDK. Use when creating a new @ai-sdk\u002F\u003Cprovider> package to integrate an AI service into the SDK.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2093,2094,2097],{"name":2060,"slug":2061,"type":15},{"name":2095,"slug":2096,"type":15},"API Development","api-development",{"name":9,"slug":8,"type":15},"2026-04-06T18:55:47.45549",{"slug":2100,"name":2100,"fn":2101,"description":2102,"org":2103,"tags":2104,"stars":2066,"repoUrl":2067,"updatedAt":2117},"adr-skill","create and maintain architecture decision records","Create and maintain Architecture Decision Records (ADRs) optimized for agentic coding workflows. Use when you need to propose, write, update, accept\u002Freject, deprecate, or supersede an ADR; bootstrap an adr folder and index; consult existing ADRs before implementing changes; or enforce ADR conventions. This skill uses Socratic questioning to capture intent before drafting, and validates output against an agent-readiness checklist.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2105,2108,2111,2114],{"name":2106,"slug":2107,"type":15},"ADR","adr",{"name":2109,"slug":2110,"type":15},"Architecture","architecture",{"name":2112,"slug":2113,"type":15},"Documentation","documentation",{"name":2115,"slug":2116,"type":15},"Engineering","engineering","2026-04-06T18:55:50.043694",{"slug":2061,"name":2061,"fn":2119,"description":2120,"org":2121,"tags":2122,"stars":2066,"repoUrl":2067,"updatedAt":2129},"build AI features with Vercel AI SDK","Answer questions about the AI SDK and help build AI-powered features. Use when developers: (1) Ask about AI SDK functions like generateText, streamText, ToolLoopAgent, embed, or tools, (2) Want to build AI agents, chatbots, RAG systems, or text generation features, (3) Have questions about AI providers (OpenAI, Anthropic, Google, etc.), streaming, tool calling, structured output, or embeddings, (4) Use React hooks like useChat or useCompletion. Triggers on: \"AI SDK\", \"Vercel AI SDK\", \"generateText\", \"streamText\", \"add AI to my app\", \"build an agent\", \"tool calling\", \"structured output\", \"useChat\".",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2123,2124,2125,2128],{"name":2076,"slug":2077,"type":15},{"name":2060,"slug":2061,"type":15},{"name":2126,"slug":2127,"type":15},"LLM","llm",{"name":9,"slug":8,"type":15},"2026-04-06T18:55:48.739463",{"slug":2131,"name":2131,"fn":2132,"description":2133,"org":2134,"tags":2135,"stars":2066,"repoUrl":2067,"updatedAt":2139},"capture-api-response-test-fixture","capture API response test fixtures","Capture API response test fixture.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2136,2137,2138],{"name":2095,"slug":2096,"type":15},{"name":2063,"slug":2064,"type":15},{"name":9,"slug":8,"type":15},"2026-04-06T18:55:56.374433",{"slug":2141,"name":2141,"fn":2142,"description":2143,"org":2144,"tags":2145,"stars":2066,"repoUrl":2067,"updatedAt":2149},"develop-ai-functions-example","develop AI SDK function examples","Develop examples for AI SDK functions. Use when creating, running, or modifying examples under examples\u002Fai-functions\u002Fsrc to validate provider support, demonstrate features, or create test fixtures.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2146,2147,2148],{"name":2060,"slug":2061,"type":15},{"name":2063,"slug":2064,"type":15},{"name":9,"slug":8,"type":15},"2026-04-06T18:55:55.088956",68]