[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-vercel-next-cache-components-optimizer":3,"mdc--6m0vtl-key":50,"related-repo-vercel-next-cache-components-optimizer":2185,"related-org-vercel-next-cache-components-optimizer":2237},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":45,"sourceUrl":48,"mdContent":49},"next-cache-components-optimizer","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},"vercel","Vercel","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fvercel.png",[12,16,17,20,23],{"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},"Caching","caching",{"name":24,"slug":25,"type":15},"Frontend","frontend",141208,"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js","2026-07-30T05:31:10.674078",null,31587,[32,33,34,35,36,37,38,39,40,41,42,43,44,8],"blog","browser","compiler","components","hybrid","nextjs","node","react","server-rendering","ssg","static","static-site-generator","universal",{"repoUrl":27,"stars":26,"forks":30,"topics":46,"description":47},[32,33,34,35,36,37,38,39,40,41,42,43,44,8],"The React Framework","https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002FHEAD\u002Fskills\u002Fnext-cache-components-optimizer","---\nname: next-cache-components-optimizer\ndescription: >\n  Drive a Next.js route to instant navigation by setting up an agentic loop,\n  under Cache Components \u002F PPR, on initial load (hard navigation) and\n  client-side navigation (soft navigation). Encode the goal as a failing\n  @next\u002Fplaywright instant() e2e and work it to green, one verified route at a\n  time; the shipped test then guards against regression. Use when asked to make\n  a route's navigation instant (its static shell commits immediately), fix a\n  route whose static shell isn't prerendered\u002Fserved\u002Fprefetched, grow a route's\n  static shell or fix its slow first paint, diagnose which Suspense boundary\n  keeps a route out of its static shell, or write the instant() e2e guard for\n  one. Requires Next.js 16.3+ with cacheComponents; directs an upgrade if older.\n---\n\n# next-cache-components-optimizer\n\nSet up an agentic optimization loop that drives a Next.js route from \"not\ninstant\" to \"instant\" and keeps it there. The loop is test-driven: encode the\ngoal as a failing `@next\u002Fplaywright` `instant()` test, work it to green, and\nship the test as the regression guard. Run it once per target route. Work the\nphases P → G in order; each ends in a gate. Fix recipes live in two lazily-read\nreferences — `reference\u002Fpatterns.md` (before→after for each blocker type) and\n`reference\u002Freal-app-patterns.md` (parallel routes, auth gates, the empty-shell\nand responsive-skeleton failure modes). Read one only when its phase points\nthere.\n\n## What is invariant, and what is yours\n\nOne thing here is fixed. The rest is yours. Read this before treating any\ncommand, platform, or env var below as a requirement.\n\n- **Invariant: the verification loop.** Maximizing the shell is worthless\n  unless you can prove it. The proof is an automated check: under a lock that\n  gates dynamic data, the static shell still commits. RED shows the gap, GREEN\n  shows it closed, the test ships as the regression guard. It must run on a\n  production-like build and must not be able to pass vacuously. Stand the loop\n  up once; every later optimization is then verifiable by construction. The\n  loop is the deliverable, not any one route.\n- **The mechanism: `@next\u002Fplaywright` `instant()`.** This skill locks with\n  [`instant()`](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Ffile-conventions\u002Froute-segment-config\u002Finstant#testing-instant-navigation):\n  a ruler, not a stopwatch (phase A). It comes from\n  `@next\u002Fplaywright` (installed alongside `@playwright\u002Ftest`, on the same\n  release line as `next`), so it isn't tied to any host. Keep it. Timing a\n  navigation by hand is too flaky to trust, and is the failure mode this skill\n  exists to prevent.\n- **Yours: the rig.** How you build, deploy, authenticate, configure\n  Playwright, and loop belongs to your stack, not to this skill. A local\n  `next build && next start`, a CI\u002Fstaging container, and a per-push preview\n  deploy are equally valid rigs; the verdict comes from the build, never the\n  platform. Phase 0 maps the invariant onto your repo. Read every platform\n  name, env-var spelling, and command below as an example to translate, not a\n  requirement.\n\n## Two navigations, two loading states\n\nA route reaches the user two ways, and both must be instant:\n\n- **Initial load (hard navigation)** commits the route's prerendered static\n  shell; deferred parts stream in behind their loading skeletons (Suspense\n  fallbacks, `loading.tsx`).\n- **Client-side navigation (soft navigation)** commits the destination's\n  prefetched App Shell — the `\u003CLink>` default under Partial Prefetching —\n  re-rendering only the segments that change.\n\nThe fix patterns are identical for both; the test differs only in how the\nnavigation is driven (\"Driving the navigation in tests\" below). The two shells\ncan differ; guard the one you ship, both when both matter\n(`reference\u002Freal-app-patterns.md`).\n\n## Goal\n\nMaximizing the static shell is the optimization objective: the most meaningful\nprerendered content commits immediately, and only genuinely per-request data\nstreams in afterward. The shipped test deterministically encodes **present ∧\ninstant**; **non-blank** is the additional bar the workflow enforces by\njudgment (D1\u002FD2\u002FE), because an `instant()` pass alone is satisfied by a blank\n`fallback={null}` shell (the empty-shell failure mode,\n`reference\u002Freal-app-patterns.md`).\n\n`instant()` is a ruler, not a stopwatch: assert that the shell appears under\nthe lock; do not time it. A trustworthy verdict requires a production build\n(phase A).\n\nThe GREEN under the lock is the deterministic verdict; each gate keeps it\ntrustworthy.\n\n## Reporting to the user\n\nThis loop is meant to run unattended — ideally across many navigations in one\npass — so it doesn't stop to ask after each route. What matters is how you word\nand present the results, not how often you interrupt. The mechanics below — the\nrig, RED, GREEN, the gates — are your scaffolding; the user never needs to hear\nthose words.\n\n- **Speak their language.** Describe the gap and the result in terms of what the\n  user sees: \"navigating to the dashboard waited on the charts query before\n  anything painted; now the layout and skeletons paint instantly and the charts\n  stream in\" — not RED\u002FGREEN, the lock, or the phase letters.\n- **Show, don't tell.** When you report a route, drive the browser (or attach\n  before\u002Fafter screenshots) so the user watches the shell commit immediately and\n  the data stream in, rather than reading a claim. Identical before and after\n  means the fix did nothing — roll it back.\n- **Present a run as a list of results,** one line per navigation — which route,\n  what's now instant, what streams — not a transcript of the loop.\n- **Only surface a question for a genuine fork:** a fix that would change\n  behavior, a security-sensitive read, or a route that's dynamic by design (a\n  runtime-prefetch candidate, not a shell to grow). A clean instant fix is not a\n  fork — keep going. With no one to ask (an unattended run), don't block: take\n  the safe default and note the assumption — for a cache-freshness choice,\n  defer the read behind `\u003CSuspense>` (always fresh, still instant) rather than\n  guess a `cacheLife`.\n\n## The workflow\n\n```\n- [ ] P  PREREQS      Next.js 16.3+ with cacheComponents: true; upgrade first → below\n- [ ] 0  SETUP        once per repo: discover + write instant-nav.rig.md     → rig-template.md\n- [ ] A  RIG          production build with the testing API exposed          → below\n- [ ] B  BASELINE     unlocked: the marker renders for the test user         → test-template.md\n- [ ] C  RED          locked instant(): the shell does not commit            → test-template.md\n- [ ] C-gate          VERIFY-RED: stop until the RED is trustworthy          → reference\u002Fred-test-robustness.md\n- [ ] D  FIX          push each Suspense boundary down to the data it guards → reference\u002Fpatterns.md\n- [ ]      D1 reuse the route's existing loading UI; do not hand-build skeletons\n- [ ]      D2 the shell matches the real render at every breakpoint  → reference\u002Freal-app-patterns.md\n- [ ] E  PARITY       the refactor changed only whether the route is instant\n- [ ] F  DIFFERENTIAL revert only the fix → RED; re-apply → GREEN            → reference\u002Fred-test-robustness.md\n- [ ] G  REVIEW       PR checklist (below)\n```\n\nPhases B and C build the test; only the locked test from C ships.\n\n---\n\n## P. PREREQUISITES: current Next.js with Cache Components\n\nThe workflow depends on framework capabilities that ship with current Next.js:\n\n- **Next.js 16.3+ with `cacheComponents: true`** in `next.config.ts`. Without\n  Cache Components there is no static shell to optimize.\n- **`@next\u002Fplaywright`** on the same release line as the project's `next`; it\n  provides `instant()`. Verify with `npm ls next @next\u002Fplaywright` (or the\n  project's package manager) and align them if they differ. The matching\n  testing API is in the `next` runtime, gated by the\n  `experimental.exposeTestingApiInProductionBuild` config flag (phase A).\n\nIf the project does not meet these, upgrade first (`npx @next\u002Fcodemod upgrade`\nautomates most of it), then enable Cache Components in `next.config.ts`:\n\n```ts\nexport default { cacheComponents: true }\n```\n\nEnabling the flag surfaces the blocking routes to resolve first; the\n[`next-cache-components-adoption`](https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-cache-components-adoption)\nskill drives that adoption. Reach for this optimizer once the app builds under\nCache Components.\n\nThis gate is deliberate: the skill targets current Next.js, and none of the\nverdicts below are meaningful on older versions.\n\n## 0. SETUP: discover this project's rig, once per repo\n\nThe principles in this skill are fixed; the infrastructure they run on is\nyours. On first use in a repository, discover how the project builds, deploys,\nauthenticates, and tests (inspect the repository first, and ask the user only\nwhat it cannot answer), then write the answers to a committed\n`instant-nav.rig.md`. Every later run reads that file instead of\nrediscovering. The six questions (BUILD \u002F EXPOSE \u002F RUN \u002F TEST USER \u002F DRIFT \u002F\nLOOP), the file template, and filled examples (local-only, generic CI +\ncontainer, preview deploy) are in **`rig-template.md`**.\n\nIf the repo has no Playwright e2e harness yet, standing up a minimal one\n(`@next\u002Fplaywright`, a config with `baseURL`, one authenticated path) is part\nof this step; the loop does not assume a pre-existing suite.\n\n## A. RIG: a production build with the testing API exposed\n\nStand up the rig described by `instant-nav.rig.md`. Two invariants hold on\nevery platform:\n\n1. **Never measure on `next dev`.** It does not prefetch, and its lock is\n   unreliable for blocking routes, so a dev `instant()` result is not a valid\n   RED or GREEN.\n2. **The measured build must expose the testing API.** Otherwise `instant()`\n   silently no-ops and the test passes vacuously (see\n   `reference\u002Fred-test-robustness.md`). The lock-engagement proof is the phase-C\n   RED itself: the unfixed target route is the known-blocking route, and its\n   RED under the lock shows the lock engages on this build (C-gate); the\n   self-validating variant in `test-template.md` is the in-band guarantee. Wire\n   `experimental.exposeTestingApiInProductionBuild` to a condition that is\n   true for every build you measure and never true in production:\n\n   ```ts\n   experimental: {\n     \u002F\u002F Use the condition your platform provides, and record it in the rig file:\n     \u002F\u002F   local:       an explicit opt-in, as below\n     \u002F\u002F   generic CI:  process.env.DEPLOY_ENV === 'staging'\n     \u002F\u002F   Vercel:      process.env.VERCEL_ENV === 'preview'\n     exposeTestingApiInProductionBuild:\n       process.env.EXPOSE_TESTING_API === '1',\n   }\n   ```\n\nThe rig is any production-like build that exposes the testing API: a local\n`next build && next start`, a CI\u002Fstaging container, and a preview deploy are\nall equally valid; the verdict comes from the build, not the platform. See\n`rig-template.md` for filled examples.\n\nFor any deployed or remote build, poll the rig's LIVENESS probe to confirm the\nartifact contains `HEAD` before trusting a verdict (a stale deploy reads as a\nfalse RED or GREEN); a local `next build && next start` needs none. The probe\nmechanism is in `rig-template.md` (question 6).\n\n## B. BASELINE (unlocked): development scaffold, do not ship\n\nDrive the real navigation with no `instant()` lock and assert that the\ndestination's `SHELL_MARKER` renders **as the test user**: the account the\ne2e suite authenticates as (in CI, the CI account; locally, your e2e login\nfixture), with its flags, plan, role, and data. This establishes that the\nmarker is real and reachable: not flag-gated, not redirected away, not a\nguessed selector. The suite runs as the test account, not the author's session;\nthat environment drift (the rig DRIFT list) is a common source of\nuntrustworthy REDs. Scaffold and run command: **`test-template.md`**.\n**Delete this baseline before the PR.**\n\n## C. RED (locked) + the VERIFY-RED gate\n\nWrap the same navigation in `instant()`; assert the shell commits under the\nlock. A RED here is the gap. **This is the test that ships**\n(`test-template.md`).\n\n> **C-gate: do not start optimizing until the RED is verified trustworthy.** A\n> RED that is red for the wrong reason sends you optimizing a route that was\n> never broken.\n\nThe question that settles it: **does `SHELL_MARKER` render without the lock,\nas the test user?** Answer it by re-running phase B as the test user, not by\nadding assertions to the shipped test. The two-branch resolution (No → marker\nor environment bug; Yes → genuine gap, proceed to D), the full taxonomy of\nuntrustworthy REDs, the checklist, and worked cases are in\n**`reference\u002Fred-test-robustness.md`**. Read it now.\n\n---\n\n## D. FIX: push each boundary down to the data it guards\n\n**The anti-pattern: one coarse boundary.** A single `\u003CSuspense>` high in the\ntree with a page-level fallback has three costs:\n\n- The layout UI stays out of the static shell: only a throwaway copy of it is\n  prerendered.\n- The entire subtree is replaced when the boundary resolves, which discards\n  client state and shifts layout.\n- The hand-built fallback drifts out of sync as the UI changes, because it\n  duplicates structure that also exists in the resolved tree.\n\n**The fix: hoist the static, push the Suspense down.** Render the layout UI\nonce, synchronously, in the shell, and wrap each await in a boundary scoped to\nthe single read it guards. Only that leaf streams; the stable ancestors are\nreused as-is.\n\n**Rule:** if an element renders in both the fallback and the resolved tree,\nhoist it above the boundary.\n\n### The most common blocker: a top-level `await` in a layout on a fallback route\n\n```\napp\u002F[locale]\u002F(app)\u002F[tenant]\u002Fdashboard\u002F...\n       │ generateStaticParams ✅   │ no generateStaticParams → fallback route\n```\n\nWhen any dynamic segment in the route lacks `generateStaticParams`, the route\nis a fallback route, and **all** params defer to request time, including the\nenumerated ones. A top-level `await` in a layout (`await params`, a\nrequest-time session read, an auth gate) then blocks the whole subtree out of\nthe static shell, even when it reads a statically known param. Minimal shape: a\ndynamic-segment route with one segment lacking `generateStaticParams`, plus a\ntop-level `await` in the layout above it.\n\n### The fix: defer the gate, render children\n\nRender `children` unconditionally; move the top-level `await` into a\n`\u003CSuspense fallback={null}>`-wrapped child. Mechanism and before→after:\n`reference\u002Freal-app-patterns.md`, \"Deferring an auth gate\".\n\n**Fix the page below the shell too, not only the layout.** A page-level\ntop-level `await` (commonly `await params`) blocks the same way the layout's\ndoes, so make the page sync and push its dynamic reads into a\n`\u003CSuspense>`-wrapped leaf as well. `fallback={null}` is correct only when a gate renders nothing on\nsuccess; for data, the fallback must be a real loading skeleton (see D1).\n\nEvery other blocker shape — `cookies()`\u002F`headers()`, uncached fetch or database\nreads, `searchParams`, metadata, viewport, non-deterministic values (`Date.now()`,\n`Math.random()`, `crypto.randomUUID()`) — surfaces its own insight when you hit\nit: the build prints a `https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002F\u003Cslug>` link. The\ndefault build output is often abbreviated and may carry no usable stack trace;\nadd `--debug-prerender` for the full failing frame and to report every blocker\npast the first. Scope the build to the route you're on with\n`next build --debug-build-paths \"app\u002F\u003Croute>\u002F**\"` rather than rebuilding the app.\nOpen that page and apply its recipe; don't improvise from the inline message.\n\nThe before→after recipe for each shape is in `reference\u002Fpatterns.md`, which maps it to the insight\nthat explains it.\n\nA few things those per-error pages don't stress for the instant-navigation goal:\n\n- **A boundary in the root layout isn't enough for client navigations.** It\n  passes a page-load check but leaves sibling client navigations blocking; put\n  the boundary below the lowest layout the source and destination routes share.\n- **Keep the LCP element** (usually the main heading) out of any boundary, so it\n  paints in the shell instead of waiting on a stream.\n- **A green check isn't always instant.** `export const instant = false` opts\n  the segment out of validation while the navigation still blocks, and a\n  `\u003CSuspense>` above the document `\u003Cbody>` prerenders an empty shell — neither\n  makes the route instant.\n\n### D1: reuse the route's existing loading UI; do not hand-build skeletons\n\nBefore writing any skeleton, search the repository for the loading UI that\nalready exists for this route, in order:\n\n1. the route's `loading.tsx`;\n2. an exported `*Skeleton` colocated with the component;\n3. the fallback already inside the component's own `\u003CSuspense>`.\n\nThe **divergence point** is the lowest layout shared by the source and\ndestination routes: a soft navigation re-renders only the segments below it,\nwhile an initial load re-runs every layout from the root. (Also called the\nshared boundary.) A `loading.tsx` above the divergence point fills only\nthe initial-load shell; it sits above the soft-nav re-render scope. A\n`loading.tsx` at the destination segment is itself the in-tree boundary for a\nsoft navigation into that segment and serves both. Reuse whichever boundary\nactually covers the navigation you are shipping; below the divergence point,\n`loading.tsx` and colocated skeletons are interchangeable for that purpose.\n\nIf a component has no skeleton, extract its loading markup into a colocated\nskeleton beside it. Do not author a fresh skeleton that mirrors the page\nlayout: it duplicates structure, drifts as the page changes, and pulls the\ndesign back toward a single coarse boundary. Reusing the component's own\nskeleton also keeps the prefetched shell consistent with the loaded UI.\n\nException: if the deferred component renders `null` for some users (for\nexample, a flag-gated control), `fallback={null}` is correct, since a skeleton\nwould flash and then collapse.\n\n### D2: the shell must match the real render at every breakpoint\n\nA skeleton frozen to one breakpoint misaligns on the others. Fix it the same\nway: one responsive component renders both the live UI and the shell (D1\nskeleton in its data slots), so the breakpoint switch happens once. Verify by\nre-asserting the shell marker at two widths\n(`await page.setViewportSize({ width: 1280, height: 800 })`, then\n`{ width: 390, height: 844 }`), or by adding a mobile Playwright project, so\nthis gate is as machine-checkable as the others. Detail:\n`reference\u002Freal-app-patterns.md`.\n\n> **D-gate: phase D is complete when the locked test from phase C passes GREEN\n> under the lock on the production-build rig**, not when the code compiles. That\n> GREEN is the deterministic stop for the fix loop; proceed to E.\n\n**When URL data can't be pushed down** (for example, the whole page depends on\n`params`, `searchParams`, or the full URL), there may be no meaningful static\nshell to grow. Don't force one. Runtime prefetching can make the soft\nnavigation instant, but it is outside this optimizer loop: it requires Partial\nPrefetching, a `\u003CLink prefetch={true}>`, and cached URL-dependent content. See\n[Runtime Prefetching](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fruntime-prefetching)\nand pattern 10 in `reference\u002Fpatterns.md` for the requirements, cost trade-offs,\nmanual prefetch caveat, and `instant()` test gotchas.\n\n## E. PARITY: the refactor changed only whether the route is instant\n\nThe push-down is a mechanical transform, not a redesign. Afterward the route\nmust render the same tree, data, ordering, empty and error states, redirects,\nand interactions as before; the only observable difference is that the shell\nnow commits instantly. Verify:\n\n- **Same render output.** The moved `await`s compute and return the same\n  values; after the stream, the route shows the same content as the base\n  branch for the test user.\n- **Side effects still fire.** A deferred `redirect()` or `notFound()` still\n  happens, at request time rather than during prerender. Confirm an\n  unauthorized user is still redirected and a missing record still returns 404.\n- **Both viewports reach the real UI** after the stream (D2).\n- **Client state survives.** Because the layout UI is hoisted into the stable\n  shell rather than swapped on resolve, open menus, scroll position, focus,\n  and input state persist across the stream.\n\nIf anything other than whether the route is instant changed, reduce the refactor.\n\n## F. DIFFERENTIAL\n\nRevert only the fix → RED; re-apply → GREEN; link both runs\n(`reference\u002Fred-test-robustness.md`). On a deployed rig, confirm each run is live\n(LIVENESS, phase A) before trusting its color.\n\n## G. REVIEW (PR checklist)\n\nA green final state means nothing if the RED was never trustworthy. The\ntest-trustworthiness items are the robustness checklist\n(`reference\u002Fred-test-robustness.md`); confirm them, then require these\nPR-specific items:\n\n- [ ] **Differential shown**: RED without the fix, GREEN with it, runs linked.\n- [ ] **Parity confirmed (E)**: same content, redirects, and state.\n- [ ] **Existing loading UI reused (D1)**: no new page-mirroring skeleton.\n- [ ] **Shell matches the real render at desktop and mobile widths (D2)**.\n\n**Stop condition for the whole workflow:** the locked test from C is GREEN on\nthe rig, the differential (F) holds, and every item above is checked. Until all\nthree hold, you are not done.\n\n## Driving the navigation in tests\n\n- **Soft navigation** → drive a real `\u003CLink>` click. **Initial load** → use\n  `page.goto()` inside `instant()` with the `baseURL` option. Do not substitute\n  `goto` for a soft-nav verdict; the two shells can differ\n  (`test-template.md`, `reference\u002Freal-app-patterns.md`).\n- With parallel routes, only the slots that change re-render on a soft\n  navigation; client-rendered navigation UI does not re-render at all. Do not\n  chase a slot the navigation never touches\n  (`reference\u002Freal-app-patterns.md`).\n\n## Files\n\n- `rig-template.md`: phase 0, the six-question rig discovery, the\n  `instant-nav.rig.md` template, and filled examples (local-only, generic CI,\n  preview deploy).\n- `test-template.md`: the shipped `instant()` specs for both navigation\n  types (phase C), and the delete-before-PR baseline scaffold (phase B).\n- `reference\u002Fred-test-robustness.md`: the C-gate and phase F. The taxonomy of\n  untrustworthy REDs, the checklist, the differential recipe, the vacuous-pass\n  failure mode, and worked cases.\n- `reference\u002Freal-app-patterns.md`: parallel routes, deferring an auth gate,\n  initial-load vs soft-navigation shells, the empty-shell failure mode, the\n  responsive-skeleton mismatch, edge cases.\n\n## After optimization\n\nOnce the target routes are instant, check whether the app has already adopted\nPartial Prefetching (`partialPrefetching: true`, or the relevant destination\nstill uses `prefetch = 'partial'` during an incremental rollout).\n\nMake that check mechanically:\n\n```bash\nrg -n \"partialPrefetching|prefetch\\s*=\\s*['\\\"]partial['\\\"]\" --glob 'next.config.*' --glob 'app\u002F**' --glob 'src\u002Fapp\u002F**'\n```\n\nIf `partialPrefetching: true` is in config, the app is globally adopted. If only\n`prefetch = 'partial'` matches, treat those destination segments as adopted\nduring an incremental rollout and keep checking any other target routes.\n\n- **Already adopted:** for any URL-data route that stopped at the limitation\n  above, consider a targeted `\u003CLink prefetch={true}>` on the links where having\n  that URL-specific content ready before the click is worth the per-link server\n  work. Keep the default link behavior everywhere else so the shared App Shell\n  remains the low-cost baseline.\n- **Not adopted yet:** recommend\n  [`next-partial-prefetching-adoption`](https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-partial-prefetching-adoption).\n  That skill moves the app onto the better prefetching model: shared App Shell\n  prefetches by default, fewer duplicated full-prefetch requests for visible\n  links, a link audit for existing `\u003CLink prefetch={true}>` usage, and optional\n  per-link runtime prefetching only where URL-specific content is worth the\n  extra server work.\n",{"data":51,"body":52},{"name":4,"description":6},{"type":53,"children":54},"root",[55,62,101,108,113,207,213,218,257,268,274,314,324,329,335,340,398,404,416,421,425,431,436,513,533,586,604,609,615,638,658,664,676,883,902,929,935,977,983,1008,1022,1051,1054,1060,1077,1095,1105,1115,1130,1139,1188,1194,1229,1267,1343,1355,1360,1415,1421,1426,1465,1498,1503,1523,1529,1556,1569,1624,1630,1635,1701,1706,1712,1724,1730,1742,1810,1820,1826,1906,1912,1969,1975,1996,2001,2110,2129,2179],{"type":56,"tag":57,"props":58,"children":59},"element","h1",{"id":4},[60],{"type":61,"value":4},"text",{"type":56,"tag":63,"props":64,"children":65},"p",{},[66,68,75,77,83,85,91,93,99],{"type":61,"value":67},"Set up an agentic optimization loop that drives a Next.js route from \"not\ninstant\" to \"instant\" and keeps it there. The loop is test-driven: encode the\ngoal as a failing ",{"type":56,"tag":69,"props":70,"children":72},"code",{"className":71},[],[73],{"type":61,"value":74},"@next\u002Fplaywright",{"type":61,"value":76}," ",{"type":56,"tag":69,"props":78,"children":80},{"className":79},[],[81],{"type":61,"value":82},"instant()",{"type":61,"value":84}," test, work it to green, and\nship the test as the regression guard. Run it once per target route. Work the\nphases P → G in order; each ends in a gate. Fix recipes live in two lazily-read\nreferences — ",{"type":56,"tag":69,"props":86,"children":88},{"className":87},[],[89],{"type":61,"value":90},"reference\u002Fpatterns.md",{"type":61,"value":92}," (before→after for each blocker type) and\n",{"type":56,"tag":69,"props":94,"children":96},{"className":95},[],[97],{"type":61,"value":98},"reference\u002Freal-app-patterns.md",{"type":61,"value":100}," (parallel routes, auth gates, the empty-shell\nand responsive-skeleton failure modes). Read one only when its phase points\nthere.",{"type":56,"tag":102,"props":103,"children":105},"h2",{"id":104},"what-is-invariant-and-what-is-yours",[106],{"type":61,"value":107},"What is invariant, and what is yours",{"type":56,"tag":63,"props":109,"children":110},{},[111],{"type":61,"value":112},"One thing here is fixed. The rest is yours. Read this before treating any\ncommand, platform, or env var below as a requirement.",{"type":56,"tag":114,"props":115,"children":116},"ul",{},[117,129,189],{"type":56,"tag":118,"props":119,"children":120},"li",{},[121,127],{"type":56,"tag":122,"props":123,"children":124},"strong",{},[125],{"type":61,"value":126},"Invariant: the verification loop.",{"type":61,"value":128}," Maximizing the shell is worthless\nunless you can prove it. The proof is an automated check: under a lock that\ngates dynamic data, the static shell still commits. RED shows the gap, GREEN\nshows it closed, the test ships as the regression guard. It must run on a\nproduction-like build and must not be able to pass vacuously. Stand the loop\nup once; every later optimization is then verifiable by construction. The\nloop is the deliverable, not any one route.",{"type":56,"tag":118,"props":130,"children":131},{},[132,150,152,164,166,171,173,179,181,187],{"type":56,"tag":122,"props":133,"children":134},{},[135,137,142,143,148],{"type":61,"value":136},"The mechanism: ",{"type":56,"tag":69,"props":138,"children":140},{"className":139},[],[141],{"type":61,"value":74},{"type":61,"value":76},{"type":56,"tag":69,"props":144,"children":146},{"className":145},[],[147],{"type":61,"value":82},{"type":61,"value":149},".",{"type":61,"value":151}," This skill locks with\n",{"type":56,"tag":153,"props":154,"children":158},"a",{"href":155,"rel":156},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fapi-reference\u002Ffile-conventions\u002Froute-segment-config\u002Finstant#testing-instant-navigation",[157],"nofollow",[159],{"type":56,"tag":69,"props":160,"children":162},{"className":161},[],[163],{"type":61,"value":82},{"type":61,"value":165},":\na ruler, not a stopwatch (phase A). It comes from\n",{"type":56,"tag":69,"props":167,"children":169},{"className":168},[],[170],{"type":61,"value":74},{"type":61,"value":172}," (installed alongside ",{"type":56,"tag":69,"props":174,"children":176},{"className":175},[],[177],{"type":61,"value":178},"@playwright\u002Ftest",{"type":61,"value":180},", on the same\nrelease line as ",{"type":56,"tag":69,"props":182,"children":184},{"className":183},[],[185],{"type":61,"value":186},"next",{"type":61,"value":188},"), so it isn't tied to any host. Keep it. Timing a\nnavigation by hand is too flaky to trust, and is the failure mode this skill\nexists to prevent.",{"type":56,"tag":118,"props":190,"children":191},{},[192,197,199,205],{"type":56,"tag":122,"props":193,"children":194},{},[195],{"type":61,"value":196},"Yours: the rig.",{"type":61,"value":198}," How you build, deploy, authenticate, configure\nPlaywright, and loop belongs to your stack, not to this skill. A local\n",{"type":56,"tag":69,"props":200,"children":202},{"className":201},[],[203],{"type":61,"value":204},"next build && next start",{"type":61,"value":206},", a CI\u002Fstaging container, and a per-push preview\ndeploy are equally valid rigs; the verdict comes from the build, never the\nplatform. Phase 0 maps the invariant onto your repo. Read every platform\nname, env-var spelling, and command below as an example to translate, not a\nrequirement.",{"type":56,"tag":102,"props":208,"children":210},{"id":209},"two-navigations-two-loading-states",[211],{"type":61,"value":212},"Two navigations, two loading states",{"type":56,"tag":63,"props":214,"children":215},{},[216],{"type":61,"value":217},"A route reaches the user two ways, and both must be instant:",{"type":56,"tag":114,"props":219,"children":220},{},[221,239],{"type":56,"tag":118,"props":222,"children":223},{},[224,229,231,237],{"type":56,"tag":122,"props":225,"children":226},{},[227],{"type":61,"value":228},"Initial load (hard navigation)",{"type":61,"value":230}," commits the route's prerendered static\nshell; deferred parts stream in behind their loading skeletons (Suspense\nfallbacks, ",{"type":56,"tag":69,"props":232,"children":234},{"className":233},[],[235],{"type":61,"value":236},"loading.tsx",{"type":61,"value":238},").",{"type":56,"tag":118,"props":240,"children":241},{},[242,247,249,255],{"type":56,"tag":122,"props":243,"children":244},{},[245],{"type":61,"value":246},"Client-side navigation (soft navigation)",{"type":61,"value":248}," commits the destination's\nprefetched App Shell — the ",{"type":56,"tag":69,"props":250,"children":252},{"className":251},[],[253],{"type":61,"value":254},"\u003CLink>",{"type":61,"value":256}," default under Partial Prefetching —\nre-rendering only the segments that change.",{"type":56,"tag":63,"props":258,"children":259},{},[260,262,267],{"type":61,"value":261},"The fix patterns are identical for both; the test differs only in how the\nnavigation is driven (\"Driving the navigation in tests\" below). The two shells\ncan differ; guard the one you ship, both when both matter\n(",{"type":56,"tag":69,"props":263,"children":265},{"className":264},[],[266],{"type":61,"value":98},{"type":61,"value":238},{"type":56,"tag":102,"props":269,"children":271},{"id":270},"goal",[272],{"type":61,"value":273},"Goal",{"type":56,"tag":63,"props":275,"children":276},{},[277,279,284,286,291,293,298,300,306,308,313],{"type":61,"value":278},"Maximizing the static shell is the optimization objective: the most meaningful\nprerendered content commits immediately, and only genuinely per-request data\nstreams in afterward. The shipped test deterministically encodes ",{"type":56,"tag":122,"props":280,"children":281},{},[282],{"type":61,"value":283},"present ∧\ninstant",{"type":61,"value":285},"; ",{"type":56,"tag":122,"props":287,"children":288},{},[289],{"type":61,"value":290},"non-blank",{"type":61,"value":292}," is the additional bar the workflow enforces by\njudgment (D1\u002FD2\u002FE), because an ",{"type":56,"tag":69,"props":294,"children":296},{"className":295},[],[297],{"type":61,"value":82},{"type":61,"value":299}," pass alone is satisfied by a blank\n",{"type":56,"tag":69,"props":301,"children":303},{"className":302},[],[304],{"type":61,"value":305},"fallback={null}",{"type":61,"value":307}," shell (the empty-shell failure mode,\n",{"type":56,"tag":69,"props":309,"children":311},{"className":310},[],[312],{"type":61,"value":98},{"type":61,"value":238},{"type":56,"tag":63,"props":315,"children":316},{},[317,322],{"type":56,"tag":69,"props":318,"children":320},{"className":319},[],[321],{"type":61,"value":82},{"type":61,"value":323}," is a ruler, not a stopwatch: assert that the shell appears under\nthe lock; do not time it. A trustworthy verdict requires a production build\n(phase A).",{"type":56,"tag":63,"props":325,"children":326},{},[327],{"type":61,"value":328},"The GREEN under the lock is the deterministic verdict; each gate keeps it\ntrustworthy.",{"type":56,"tag":102,"props":330,"children":332},{"id":331},"reporting-to-the-user",[333],{"type":61,"value":334},"Reporting to the user",{"type":56,"tag":63,"props":336,"children":337},{},[338],{"type":61,"value":339},"This loop is meant to run unattended — ideally across many navigations in one\npass — so it doesn't stop to ask after each route. What matters is how you word\nand present the results, not how often you interrupt. The mechanics below — the\nrig, RED, GREEN, the gates — are your scaffolding; the user never needs to hear\nthose words.",{"type":56,"tag":114,"props":341,"children":342},{},[343,353,363,373],{"type":56,"tag":118,"props":344,"children":345},{},[346,351],{"type":56,"tag":122,"props":347,"children":348},{},[349],{"type":61,"value":350},"Speak their language.",{"type":61,"value":352}," Describe the gap and the result in terms of what the\nuser sees: \"navigating to the dashboard waited on the charts query before\nanything painted; now the layout and skeletons paint instantly and the charts\nstream in\" — not RED\u002FGREEN, the lock, or the phase letters.",{"type":56,"tag":118,"props":354,"children":355},{},[356,361],{"type":56,"tag":122,"props":357,"children":358},{},[359],{"type":61,"value":360},"Show, don't tell.",{"type":61,"value":362}," When you report a route, drive the browser (or attach\nbefore\u002Fafter screenshots) so the user watches the shell commit immediately and\nthe data stream in, rather than reading a claim. Identical before and after\nmeans the fix did nothing — roll it back.",{"type":56,"tag":118,"props":364,"children":365},{},[366,371],{"type":56,"tag":122,"props":367,"children":368},{},[369],{"type":61,"value":370},"Present a run as a list of results,",{"type":61,"value":372}," one line per navigation — which route,\nwhat's now instant, what streams — not a transcript of the loop.",{"type":56,"tag":118,"props":374,"children":375},{},[376,381,383,389,391,397],{"type":56,"tag":122,"props":377,"children":378},{},[379],{"type":61,"value":380},"Only surface a question for a genuine fork:",{"type":61,"value":382}," a fix that would change\nbehavior, a security-sensitive read, or a route that's dynamic by design (a\nruntime-prefetch candidate, not a shell to grow). A clean instant fix is not a\nfork — keep going. With no one to ask (an unattended run), don't block: take\nthe safe default and note the assumption — for a cache-freshness choice,\ndefer the read behind ",{"type":56,"tag":69,"props":384,"children":386},{"className":385},[],[387],{"type":61,"value":388},"\u003CSuspense>",{"type":61,"value":390}," (always fresh, still instant) rather than\nguess a ",{"type":56,"tag":69,"props":392,"children":394},{"className":393},[],[395],{"type":61,"value":396},"cacheLife",{"type":61,"value":149},{"type":56,"tag":102,"props":399,"children":401},{"id":400},"the-workflow",[402],{"type":61,"value":403},"The workflow",{"type":56,"tag":405,"props":406,"children":410},"pre",{"className":407,"code":409,"language":61},[408],"language-text","- [ ] P  PREREQS      Next.js 16.3+ with cacheComponents: true; upgrade first → below\n- [ ] 0  SETUP        once per repo: discover + write instant-nav.rig.md     → rig-template.md\n- [ ] A  RIG          production build with the testing API exposed          → below\n- [ ] B  BASELINE     unlocked: the marker renders for the test user         → test-template.md\n- [ ] C  RED          locked instant(): the shell does not commit            → test-template.md\n- [ ] C-gate          VERIFY-RED: stop until the RED is trustworthy          → reference\u002Fred-test-robustness.md\n- [ ] D  FIX          push each Suspense boundary down to the data it guards → reference\u002Fpatterns.md\n- [ ]      D1 reuse the route's existing loading UI; do not hand-build skeletons\n- [ ]      D2 the shell matches the real render at every breakpoint  → reference\u002Freal-app-patterns.md\n- [ ] E  PARITY       the refactor changed only whether the route is instant\n- [ ] F  DIFFERENTIAL revert only the fix → RED; re-apply → GREEN            → reference\u002Fred-test-robustness.md\n- [ ] G  REVIEW       PR checklist (below)\n",[411],{"type":56,"tag":69,"props":412,"children":414},{"__ignoreMap":413},"",[415],{"type":61,"value":409},{"type":56,"tag":63,"props":417,"children":418},{},[419],{"type":61,"value":420},"Phases B and C build the test; only the locked test from C ships.",{"type":56,"tag":422,"props":423,"children":424},"hr",{},[],{"type":56,"tag":102,"props":426,"children":428},{"id":427},"p-prerequisites-current-nextjs-with-cache-components",[429],{"type":61,"value":430},"P. PREREQUISITES: current Next.js with Cache Components",{"type":56,"tag":63,"props":432,"children":433},{},[434],{"type":61,"value":435},"The workflow depends on framework capabilities that ship with current Next.js:",{"type":56,"tag":114,"props":437,"children":438},{},[439,463],{"type":56,"tag":118,"props":440,"children":441},{},[442,453,455,461],{"type":56,"tag":122,"props":443,"children":444},{},[445,447],{"type":61,"value":446},"Next.js 16.3+ with ",{"type":56,"tag":69,"props":448,"children":450},{"className":449},[],[451],{"type":61,"value":452},"cacheComponents: true",{"type":61,"value":454}," in ",{"type":56,"tag":69,"props":456,"children":458},{"className":457},[],[459],{"type":61,"value":460},"next.config.ts",{"type":61,"value":462},". Without\nCache Components there is no static shell to optimize.",{"type":56,"tag":118,"props":464,"children":465},{},[466,474,476,481,483,488,490,496,498,503,505,511],{"type":56,"tag":122,"props":467,"children":468},{},[469],{"type":56,"tag":69,"props":470,"children":472},{"className":471},[],[473],{"type":61,"value":74},{"type":61,"value":475}," on the same release line as the project's ",{"type":56,"tag":69,"props":477,"children":479},{"className":478},[],[480],{"type":61,"value":186},{"type":61,"value":482},"; it\nprovides ",{"type":56,"tag":69,"props":484,"children":486},{"className":485},[],[487],{"type":61,"value":82},{"type":61,"value":489},". Verify with ",{"type":56,"tag":69,"props":491,"children":493},{"className":492},[],[494],{"type":61,"value":495},"npm ls next @next\u002Fplaywright",{"type":61,"value":497}," (or the\nproject's package manager) and align them if they differ. The matching\ntesting API is in the ",{"type":56,"tag":69,"props":499,"children":501},{"className":500},[],[502],{"type":61,"value":186},{"type":61,"value":504}," runtime, gated by the\n",{"type":56,"tag":69,"props":506,"children":508},{"className":507},[],[509],{"type":61,"value":510},"experimental.exposeTestingApiInProductionBuild",{"type":61,"value":512}," config flag (phase A).",{"type":56,"tag":63,"props":514,"children":515},{},[516,518,524,526,531],{"type":61,"value":517},"If the project does not meet these, upgrade first (",{"type":56,"tag":69,"props":519,"children":521},{"className":520},[],[522],{"type":61,"value":523},"npx @next\u002Fcodemod upgrade",{"type":61,"value":525},"\nautomates most of it), then enable Cache Components in ",{"type":56,"tag":69,"props":527,"children":529},{"className":528},[],[530],{"type":61,"value":460},{"type":61,"value":532},":",{"type":56,"tag":405,"props":534,"children":538},{"className":535,"code":536,"language":537,"meta":413,"style":413},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default { cacheComponents: true }\n","ts",[539],{"type":56,"tag":69,"props":540,"children":541},{"__ignoreMap":413},[542],{"type":56,"tag":543,"props":544,"children":547},"span",{"class":545,"line":546},"line",1,[548,554,559,565,571,575,581],{"type":56,"tag":543,"props":549,"children":551},{"style":550},"--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic",[552],{"type":61,"value":553},"export",{"type":56,"tag":543,"props":555,"children":556},{"style":550},[557],{"type":61,"value":558}," default",{"type":56,"tag":543,"props":560,"children":562},{"style":561},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[563],{"type":61,"value":564}," {",{"type":56,"tag":543,"props":566,"children":568},{"style":567},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[569],{"type":61,"value":570}," cacheComponents",{"type":56,"tag":543,"props":572,"children":573},{"style":561},[574],{"type":61,"value":532},{"type":56,"tag":543,"props":576,"children":578},{"style":577},"--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC",[579],{"type":61,"value":580}," true",{"type":56,"tag":543,"props":582,"children":583},{"style":561},[584],{"type":61,"value":585}," }\n",{"type":56,"tag":63,"props":587,"children":588},{},[589,591,602],{"type":61,"value":590},"Enabling the flag surfaces the blocking routes to resolve first; the\n",{"type":56,"tag":153,"props":592,"children":595},{"href":593,"rel":594},"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-cache-components-adoption",[157],[596],{"type":56,"tag":69,"props":597,"children":599},{"className":598},[],[600],{"type":61,"value":601},"next-cache-components-adoption",{"type":61,"value":603},"\nskill drives that adoption. Reach for this optimizer once the app builds under\nCache Components.",{"type":56,"tag":63,"props":605,"children":606},{},[607],{"type":61,"value":608},"This gate is deliberate: the skill targets current Next.js, and none of the\nverdicts below are meaningful on older versions.",{"type":56,"tag":102,"props":610,"children":612},{"id":611},"_0-setup-discover-this-projects-rig-once-per-repo",[613],{"type":61,"value":614},"0. SETUP: discover this project's rig, once per repo",{"type":56,"tag":63,"props":616,"children":617},{},[618,620,626,628,637],{"type":61,"value":619},"The principles in this skill are fixed; the infrastructure they run on is\nyours. On first use in a repository, discover how the project builds, deploys,\nauthenticates, and tests (inspect the repository first, and ask the user only\nwhat it cannot answer), then write the answers to a committed\n",{"type":56,"tag":69,"props":621,"children":623},{"className":622},[],[624],{"type":61,"value":625},"instant-nav.rig.md",{"type":61,"value":627},". Every later run reads that file instead of\nrediscovering. The six questions (BUILD \u002F EXPOSE \u002F RUN \u002F TEST USER \u002F DRIFT \u002F\nLOOP), the file template, and filled examples (local-only, generic CI +\ncontainer, preview deploy) are in ",{"type":56,"tag":122,"props":629,"children":630},{},[631],{"type":56,"tag":69,"props":632,"children":634},{"className":633},[],[635],{"type":61,"value":636},"rig-template.md",{"type":61,"value":149},{"type":56,"tag":63,"props":639,"children":640},{},[641,643,648,650,656],{"type":61,"value":642},"If the repo has no Playwright e2e harness yet, standing up a minimal one\n(",{"type":56,"tag":69,"props":644,"children":646},{"className":645},[],[647],{"type":61,"value":74},{"type":61,"value":649},", a config with ",{"type":56,"tag":69,"props":651,"children":653},{"className":652},[],[654],{"type":61,"value":655},"baseURL",{"type":61,"value":657},", one authenticated path) is part\nof this step; the loop does not assume a pre-existing suite.",{"type":56,"tag":102,"props":659,"children":661},{"id":660},"a-rig-a-production-build-with-the-testing-api-exposed",[662],{"type":61,"value":663},"A. RIG: a production build with the testing API exposed",{"type":56,"tag":63,"props":665,"children":666},{},[667,669,674],{"type":61,"value":668},"Stand up the rig described by ",{"type":56,"tag":69,"props":670,"children":672},{"className":671},[],[673],{"type":61,"value":625},{"type":61,"value":675},". Two invariants hold on\nevery platform:",{"type":56,"tag":677,"props":678,"children":679},"ol",{},[680,704],{"type":56,"tag":118,"props":681,"children":682},{},[683,695,697,702],{"type":56,"tag":122,"props":684,"children":685},{},[686,688,694],{"type":61,"value":687},"Never measure on ",{"type":56,"tag":69,"props":689,"children":691},{"className":690},[],[692],{"type":61,"value":693},"next dev",{"type":61,"value":149},{"type":61,"value":696}," It does not prefetch, and its lock is\nunreliable for blocking routes, so a dev ",{"type":56,"tag":69,"props":698,"children":700},{"className":699},[],[701],{"type":61,"value":82},{"type":61,"value":703}," result is not a valid\nRED or GREEN.",{"type":56,"tag":118,"props":705,"children":706},{},[707,712,714,719,721,727,729,735,737,742,744],{"type":56,"tag":122,"props":708,"children":709},{},[710],{"type":61,"value":711},"The measured build must expose the testing API.",{"type":61,"value":713}," Otherwise ",{"type":56,"tag":69,"props":715,"children":717},{"className":716},[],[718],{"type":61,"value":82},{"type":61,"value":720},"\nsilently no-ops and the test passes vacuously (see\n",{"type":56,"tag":69,"props":722,"children":724},{"className":723},[],[725],{"type":61,"value":726},"reference\u002Fred-test-robustness.md",{"type":61,"value":728},"). The lock-engagement proof is the phase-C\nRED itself: the unfixed target route is the known-blocking route, and its\nRED under the lock shows the lock engages on this build (C-gate); the\nself-validating variant in ",{"type":56,"tag":69,"props":730,"children":732},{"className":731},[],[733],{"type":61,"value":734},"test-template.md",{"type":61,"value":736}," is the in-band guarantee. Wire\n",{"type":56,"tag":69,"props":738,"children":740},{"className":739},[],[741],{"type":61,"value":510},{"type":61,"value":743}," to a condition that is\ntrue for every build you measure and never true in production:",{"type":56,"tag":405,"props":745,"children":747},{"className":535,"code":746,"language":537,"meta":413,"style":413},"experimental: {\n  \u002F\u002F Use the condition your platform provides, and record it in the rig file:\n  \u002F\u002F   local:       an explicit opt-in, as below\n  \u002F\u002F   generic CI:  process.env.DEPLOY_ENV === 'staging'\n  \u002F\u002F   Vercel:      process.env.VERCEL_ENV === 'preview'\n  exposeTestingApiInProductionBuild:\n    process.env.EXPOSE_TESTING_API === '1',\n}\n",[748],{"type":56,"tag":69,"props":749,"children":750},{"__ignoreMap":413},[751,769,779,788,797,806,820,874],{"type":56,"tag":543,"props":752,"children":753},{"class":545,"line":546},[754,760,764],{"type":56,"tag":543,"props":755,"children":757},{"style":756},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[758],{"type":61,"value":759},"experimental",{"type":56,"tag":543,"props":761,"children":762},{"style":561},[763],{"type":61,"value":532},{"type":56,"tag":543,"props":765,"children":766},{"style":561},[767],{"type":61,"value":768}," {\n",{"type":56,"tag":543,"props":770,"children":772},{"class":545,"line":771},2,[773],{"type":56,"tag":543,"props":774,"children":776},{"style":775},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic",[777],{"type":61,"value":778},"  \u002F\u002F Use the condition your platform provides, and record it in the rig file:\n",{"type":56,"tag":543,"props":780,"children":782},{"class":545,"line":781},3,[783],{"type":56,"tag":543,"props":784,"children":785},{"style":775},[786],{"type":61,"value":787},"  \u002F\u002F   local:       an explicit opt-in, as below\n",{"type":56,"tag":543,"props":789,"children":791},{"class":545,"line":790},4,[792],{"type":56,"tag":543,"props":793,"children":794},{"style":775},[795],{"type":61,"value":796},"  \u002F\u002F   generic CI:  process.env.DEPLOY_ENV === 'staging'\n",{"type":56,"tag":543,"props":798,"children":800},{"class":545,"line":799},5,[801],{"type":56,"tag":543,"props":802,"children":803},{"style":775},[804],{"type":61,"value":805},"  \u002F\u002F   Vercel:      process.env.VERCEL_ENV === 'preview'\n",{"type":56,"tag":543,"props":807,"children":809},{"class":545,"line":808},6,[810,815],{"type":56,"tag":543,"props":811,"children":812},{"style":756},[813],{"type":61,"value":814},"  exposeTestingApiInProductionBuild",{"type":56,"tag":543,"props":816,"children":817},{"style":561},[818],{"type":61,"value":819},":\n",{"type":56,"tag":543,"props":821,"children":823},{"class":545,"line":822},7,[824,830,834,839,843,848,853,858,864,869],{"type":56,"tag":543,"props":825,"children":827},{"style":826},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[828],{"type":61,"value":829},"    process",{"type":56,"tag":543,"props":831,"children":832},{"style":561},[833],{"type":61,"value":149},{"type":56,"tag":543,"props":835,"children":836},{"style":826},[837],{"type":61,"value":838},"env",{"type":56,"tag":543,"props":840,"children":841},{"style":561},[842],{"type":61,"value":149},{"type":56,"tag":543,"props":844,"children":845},{"style":826},[846],{"type":61,"value":847},"EXPOSE_TESTING_API",{"type":56,"tag":543,"props":849,"children":850},{"style":561},[851],{"type":61,"value":852}," ===",{"type":56,"tag":543,"props":854,"children":855},{"style":561},[856],{"type":61,"value":857}," '",{"type":56,"tag":543,"props":859,"children":861},{"style":860},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[862],{"type":61,"value":863},"1",{"type":56,"tag":543,"props":865,"children":866},{"style":561},[867],{"type":61,"value":868},"'",{"type":56,"tag":543,"props":870,"children":871},{"style":561},[872],{"type":61,"value":873},",\n",{"type":56,"tag":543,"props":875,"children":877},{"class":545,"line":876},8,[878],{"type":56,"tag":543,"props":879,"children":880},{"style":561},[881],{"type":61,"value":882},"}\n",{"type":56,"tag":63,"props":884,"children":885},{},[886,888,893,895,900],{"type":61,"value":887},"The rig is any production-like build that exposes the testing API: a local\n",{"type":56,"tag":69,"props":889,"children":891},{"className":890},[],[892],{"type":61,"value":204},{"type":61,"value":894},", a CI\u002Fstaging container, and a preview deploy are\nall equally valid; the verdict comes from the build, not the platform. See\n",{"type":56,"tag":69,"props":896,"children":898},{"className":897},[],[899],{"type":61,"value":636},{"type":61,"value":901}," for filled examples.",{"type":56,"tag":63,"props":903,"children":904},{},[905,907,913,915,920,922,927],{"type":61,"value":906},"For any deployed or remote build, poll the rig's LIVENESS probe to confirm the\nartifact contains ",{"type":56,"tag":69,"props":908,"children":910},{"className":909},[],[911],{"type":61,"value":912},"HEAD",{"type":61,"value":914}," before trusting a verdict (a stale deploy reads as a\nfalse RED or GREEN); a local ",{"type":56,"tag":69,"props":916,"children":918},{"className":917},[],[919],{"type":61,"value":204},{"type":61,"value":921}," needs none. The probe\nmechanism is in ",{"type":56,"tag":69,"props":923,"children":925},{"className":924},[],[926],{"type":61,"value":636},{"type":61,"value":928}," (question 6).",{"type":56,"tag":102,"props":930,"children":932},{"id":931},"b-baseline-unlocked-development-scaffold-do-not-ship",[933],{"type":61,"value":934},"B. BASELINE (unlocked): development scaffold, do not ship",{"type":56,"tag":63,"props":936,"children":937},{},[938,940,945,947,953,955,960,962,970,972],{"type":61,"value":939},"Drive the real navigation with no ",{"type":56,"tag":69,"props":941,"children":943},{"className":942},[],[944],{"type":61,"value":82},{"type":61,"value":946}," lock and assert that the\ndestination's ",{"type":56,"tag":69,"props":948,"children":950},{"className":949},[],[951],{"type":61,"value":952},"SHELL_MARKER",{"type":61,"value":954}," renders ",{"type":56,"tag":122,"props":956,"children":957},{},[958],{"type":61,"value":959},"as the test user",{"type":61,"value":961},": the account the\ne2e suite authenticates as (in CI, the CI account; locally, your e2e login\nfixture), with its flags, plan, role, and data. This establishes that the\nmarker is real and reachable: not flag-gated, not redirected away, not a\nguessed selector. The suite runs as the test account, not the author's session;\nthat environment drift (the rig DRIFT list) is a common source of\nuntrustworthy REDs. Scaffold and run command: ",{"type":56,"tag":122,"props":963,"children":964},{},[965],{"type":56,"tag":69,"props":966,"children":968},{"className":967},[],[969],{"type":61,"value":734},{"type":61,"value":971},".\n",{"type":56,"tag":122,"props":973,"children":974},{},[975],{"type":61,"value":976},"Delete this baseline before the PR.",{"type":56,"tag":102,"props":978,"children":980},{"id":979},"c-red-locked-the-verify-red-gate",[981],{"type":61,"value":982},"C. RED (locked) + the VERIFY-RED gate",{"type":56,"tag":63,"props":984,"children":985},{},[986,988,993,995,1000,1002,1007],{"type":61,"value":987},"Wrap the same navigation in ",{"type":56,"tag":69,"props":989,"children":991},{"className":990},[],[992],{"type":61,"value":82},{"type":61,"value":994},"; assert the shell commits under the\nlock. A RED here is the gap. ",{"type":56,"tag":122,"props":996,"children":997},{},[998],{"type":61,"value":999},"This is the test that ships",{"type":61,"value":1001},"\n(",{"type":56,"tag":69,"props":1003,"children":1005},{"className":1004},[],[1006],{"type":61,"value":734},{"type":61,"value":238},{"type":56,"tag":1009,"props":1010,"children":1011},"blockquote",{},[1012],{"type":56,"tag":63,"props":1013,"children":1014},{},[1015,1020],{"type":56,"tag":122,"props":1016,"children":1017},{},[1018],{"type":61,"value":1019},"C-gate: do not start optimizing until the RED is verified trustworthy.",{"type":61,"value":1021}," A\nRED that is red for the wrong reason sends you optimizing a route that was\nnever broken.",{"type":56,"tag":63,"props":1023,"children":1024},{},[1025,1027,1039,1041,1049],{"type":61,"value":1026},"The question that settles it: ",{"type":56,"tag":122,"props":1028,"children":1029},{},[1030,1032,1037],{"type":61,"value":1031},"does ",{"type":56,"tag":69,"props":1033,"children":1035},{"className":1034},[],[1036],{"type":61,"value":952},{"type":61,"value":1038}," render without the lock,\nas the test user?",{"type":61,"value":1040}," Answer it by re-running phase B as the test user, not by\nadding assertions to the shipped test. The two-branch resolution (No → marker\nor environment bug; Yes → genuine gap, proceed to D), the full taxonomy of\nuntrustworthy REDs, the checklist, and worked cases are in\n",{"type":56,"tag":122,"props":1042,"children":1043},{},[1044],{"type":56,"tag":69,"props":1045,"children":1047},{"className":1046},[],[1048],{"type":61,"value":726},{"type":61,"value":1050},". Read it now.",{"type":56,"tag":422,"props":1052,"children":1053},{},[],{"type":56,"tag":102,"props":1055,"children":1057},{"id":1056},"d-fix-push-each-boundary-down-to-the-data-it-guards",[1058],{"type":61,"value":1059},"D. FIX: push each boundary down to the data it guards",{"type":56,"tag":63,"props":1061,"children":1062},{},[1063,1068,1070,1075],{"type":56,"tag":122,"props":1064,"children":1065},{},[1066],{"type":61,"value":1067},"The anti-pattern: one coarse boundary.",{"type":61,"value":1069}," A single ",{"type":56,"tag":69,"props":1071,"children":1073},{"className":1072},[],[1074],{"type":61,"value":388},{"type":61,"value":1076}," high in the\ntree with a page-level fallback has three costs:",{"type":56,"tag":114,"props":1078,"children":1079},{},[1080,1085,1090],{"type":56,"tag":118,"props":1081,"children":1082},{},[1083],{"type":61,"value":1084},"The layout UI stays out of the static shell: only a throwaway copy of it is\nprerendered.",{"type":56,"tag":118,"props":1086,"children":1087},{},[1088],{"type":61,"value":1089},"The entire subtree is replaced when the boundary resolves, which discards\nclient state and shifts layout.",{"type":56,"tag":118,"props":1091,"children":1092},{},[1093],{"type":61,"value":1094},"The hand-built fallback drifts out of sync as the UI changes, because it\nduplicates structure that also exists in the resolved tree.",{"type":56,"tag":63,"props":1096,"children":1097},{},[1098,1103],{"type":56,"tag":122,"props":1099,"children":1100},{},[1101],{"type":61,"value":1102},"The fix: hoist the static, push the Suspense down.",{"type":61,"value":1104}," Render the layout UI\nonce, synchronously, in the shell, and wrap each await in a boundary scoped to\nthe single read it guards. Only that leaf streams; the stable ancestors are\nreused as-is.",{"type":56,"tag":63,"props":1106,"children":1107},{},[1108,1113],{"type":56,"tag":122,"props":1109,"children":1110},{},[1111],{"type":61,"value":1112},"Rule:",{"type":61,"value":1114}," if an element renders in both the fallback and the resolved tree,\nhoist it above the boundary.",{"type":56,"tag":1116,"props":1117,"children":1119},"h3",{"id":1118},"the-most-common-blocker-a-top-level-await-in-a-layout-on-a-fallback-route",[1120,1122,1128],{"type":61,"value":1121},"The most common blocker: a top-level ",{"type":56,"tag":69,"props":1123,"children":1125},{"className":1124},[],[1126],{"type":61,"value":1127},"await",{"type":61,"value":1129}," in a layout on a fallback route",{"type":56,"tag":405,"props":1131,"children":1134},{"className":1132,"code":1133,"language":61},[408],"app\u002F[locale]\u002F(app)\u002F[tenant]\u002Fdashboard\u002F...\n       │ generateStaticParams ✅   │ no generateStaticParams → fallback route\n",[1135],{"type":56,"tag":69,"props":1136,"children":1137},{"__ignoreMap":413},[1138],{"type":61,"value":1133},{"type":56,"tag":63,"props":1140,"children":1141},{},[1142,1144,1150,1152,1157,1159,1164,1166,1172,1174,1179,1181,1186],{"type":61,"value":1143},"When any dynamic segment in the route lacks ",{"type":56,"tag":69,"props":1145,"children":1147},{"className":1146},[],[1148],{"type":61,"value":1149},"generateStaticParams",{"type":61,"value":1151},", the route\nis a fallback route, and ",{"type":56,"tag":122,"props":1153,"children":1154},{},[1155],{"type":61,"value":1156},"all",{"type":61,"value":1158}," params defer to request time, including the\nenumerated ones. A top-level ",{"type":56,"tag":69,"props":1160,"children":1162},{"className":1161},[],[1163],{"type":61,"value":1127},{"type":61,"value":1165}," in a layout (",{"type":56,"tag":69,"props":1167,"children":1169},{"className":1168},[],[1170],{"type":61,"value":1171},"await params",{"type":61,"value":1173},", a\nrequest-time session read, an auth gate) then blocks the whole subtree out of\nthe static shell, even when it reads a statically known param. Minimal shape: a\ndynamic-segment route with one segment lacking ",{"type":56,"tag":69,"props":1175,"children":1177},{"className":1176},[],[1178],{"type":61,"value":1149},{"type":61,"value":1180},", plus a\ntop-level ",{"type":56,"tag":69,"props":1182,"children":1184},{"className":1183},[],[1185],{"type":61,"value":1127},{"type":61,"value":1187}," in the layout above it.",{"type":56,"tag":1116,"props":1189,"children":1191},{"id":1190},"the-fix-defer-the-gate-render-children",[1192],{"type":61,"value":1193},"The fix: defer the gate, render children",{"type":56,"tag":63,"props":1195,"children":1196},{},[1197,1199,1205,1207,1212,1214,1220,1222,1227],{"type":61,"value":1198},"Render ",{"type":56,"tag":69,"props":1200,"children":1202},{"className":1201},[],[1203],{"type":61,"value":1204},"children",{"type":61,"value":1206}," unconditionally; move the top-level ",{"type":56,"tag":69,"props":1208,"children":1210},{"className":1209},[],[1211],{"type":61,"value":1127},{"type":61,"value":1213}," into a\n",{"type":56,"tag":69,"props":1215,"children":1217},{"className":1216},[],[1218],{"type":61,"value":1219},"\u003CSuspense fallback={null}>",{"type":61,"value":1221},"-wrapped child. Mechanism and before→after:\n",{"type":56,"tag":69,"props":1223,"children":1225},{"className":1224},[],[1226],{"type":61,"value":98},{"type":61,"value":1228},", \"Deferring an auth gate\".",{"type":56,"tag":63,"props":1230,"children":1231},{},[1232,1237,1239,1244,1246,1251,1253,1258,1260,1265],{"type":56,"tag":122,"props":1233,"children":1234},{},[1235],{"type":61,"value":1236},"Fix the page below the shell too, not only the layout.",{"type":61,"value":1238}," A page-level\ntop-level ",{"type":56,"tag":69,"props":1240,"children":1242},{"className":1241},[],[1243],{"type":61,"value":1127},{"type":61,"value":1245}," (commonly ",{"type":56,"tag":69,"props":1247,"children":1249},{"className":1248},[],[1250],{"type":61,"value":1171},{"type":61,"value":1252},") blocks the same way the layout's\ndoes, so make the page sync and push its dynamic reads into a\n",{"type":56,"tag":69,"props":1254,"children":1256},{"className":1255},[],[1257],{"type":61,"value":388},{"type":61,"value":1259},"-wrapped leaf as well. ",{"type":56,"tag":69,"props":1261,"children":1263},{"className":1262},[],[1264],{"type":61,"value":305},{"type":61,"value":1266}," is correct only when a gate renders nothing on\nsuccess; for data, the fallback must be a real loading skeleton (see D1).",{"type":56,"tag":63,"props":1268,"children":1269},{},[1270,1272,1278,1280,1286,1288,1294,1296,1302,1303,1309,1311,1317,1319,1325,1327,1333,1335,1341],{"type":61,"value":1271},"Every other blocker shape — ",{"type":56,"tag":69,"props":1273,"children":1275},{"className":1274},[],[1276],{"type":61,"value":1277},"cookies()",{"type":61,"value":1279},"\u002F",{"type":56,"tag":69,"props":1281,"children":1283},{"className":1282},[],[1284],{"type":61,"value":1285},"headers()",{"type":61,"value":1287},", uncached fetch or database\nreads, ",{"type":56,"tag":69,"props":1289,"children":1291},{"className":1290},[],[1292],{"type":61,"value":1293},"searchParams",{"type":61,"value":1295},", metadata, viewport, non-deterministic values (",{"type":56,"tag":69,"props":1297,"children":1299},{"className":1298},[],[1300],{"type":61,"value":1301},"Date.now()",{"type":61,"value":873},{"type":56,"tag":69,"props":1304,"children":1306},{"className":1305},[],[1307],{"type":61,"value":1308},"Math.random()",{"type":61,"value":1310},", ",{"type":56,"tag":69,"props":1312,"children":1314},{"className":1313},[],[1315],{"type":61,"value":1316},"crypto.randomUUID()",{"type":61,"value":1318},") — surfaces its own insight when you hit\nit: the build prints a ",{"type":56,"tag":69,"props":1320,"children":1322},{"className":1321},[],[1323],{"type":61,"value":1324},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fmessages\u002F\u003Cslug>",{"type":61,"value":1326}," link. The\ndefault build output is often abbreviated and may carry no usable stack trace;\nadd ",{"type":56,"tag":69,"props":1328,"children":1330},{"className":1329},[],[1331],{"type":61,"value":1332},"--debug-prerender",{"type":61,"value":1334}," for the full failing frame and to report every blocker\npast the first. Scope the build to the route you're on with\n",{"type":56,"tag":69,"props":1336,"children":1338},{"className":1337},[],[1339],{"type":61,"value":1340},"next build --debug-build-paths \"app\u002F\u003Croute>\u002F**\"",{"type":61,"value":1342}," rather than rebuilding the app.\nOpen that page and apply its recipe; don't improvise from the inline message.",{"type":56,"tag":63,"props":1344,"children":1345},{},[1346,1348,1353],{"type":61,"value":1347},"The before→after recipe for each shape is in ",{"type":56,"tag":69,"props":1349,"children":1351},{"className":1350},[],[1352],{"type":61,"value":90},{"type":61,"value":1354},", which maps it to the insight\nthat explains it.",{"type":56,"tag":63,"props":1356,"children":1357},{},[1358],{"type":61,"value":1359},"A few things those per-error pages don't stress for the instant-navigation goal:",{"type":56,"tag":114,"props":1361,"children":1362},{},[1363,1373,1383],{"type":56,"tag":118,"props":1364,"children":1365},{},[1366,1371],{"type":56,"tag":122,"props":1367,"children":1368},{},[1369],{"type":61,"value":1370},"A boundary in the root layout isn't enough for client navigations.",{"type":61,"value":1372}," It\npasses a page-load check but leaves sibling client navigations blocking; put\nthe boundary below the lowest layout the source and destination routes share.",{"type":56,"tag":118,"props":1374,"children":1375},{},[1376,1381],{"type":56,"tag":122,"props":1377,"children":1378},{},[1379],{"type":61,"value":1380},"Keep the LCP element",{"type":61,"value":1382}," (usually the main heading) out of any boundary, so it\npaints in the shell instead of waiting on a stream.",{"type":56,"tag":118,"props":1384,"children":1385},{},[1386,1391,1392,1398,1400,1405,1407,1413],{"type":56,"tag":122,"props":1387,"children":1388},{},[1389],{"type":61,"value":1390},"A green check isn't always instant.",{"type":61,"value":76},{"type":56,"tag":69,"props":1393,"children":1395},{"className":1394},[],[1396],{"type":61,"value":1397},"export const instant = false",{"type":61,"value":1399}," opts\nthe segment out of validation while the navigation still blocks, and a\n",{"type":56,"tag":69,"props":1401,"children":1403},{"className":1402},[],[1404],{"type":61,"value":388},{"type":61,"value":1406}," above the document ",{"type":56,"tag":69,"props":1408,"children":1410},{"className":1409},[],[1411],{"type":61,"value":1412},"\u003Cbody>",{"type":61,"value":1414}," prerenders an empty shell — neither\nmakes the route instant.",{"type":56,"tag":1116,"props":1416,"children":1418},{"id":1417},"d1-reuse-the-routes-existing-loading-ui-do-not-hand-build-skeletons",[1419],{"type":61,"value":1420},"D1: reuse the route's existing loading UI; do not hand-build skeletons",{"type":56,"tag":63,"props":1422,"children":1423},{},[1424],{"type":61,"value":1425},"Before writing any skeleton, search the repository for the loading UI that\nalready exists for this route, in order:",{"type":56,"tag":677,"props":1427,"children":1428},{},[1429,1441,1454],{"type":56,"tag":118,"props":1430,"children":1431},{},[1432,1434,1439],{"type":61,"value":1433},"the route's ",{"type":56,"tag":69,"props":1435,"children":1437},{"className":1436},[],[1438],{"type":61,"value":236},{"type":61,"value":1440},";",{"type":56,"tag":118,"props":1442,"children":1443},{},[1444,1446,1452],{"type":61,"value":1445},"an exported ",{"type":56,"tag":69,"props":1447,"children":1449},{"className":1448},[],[1450],{"type":61,"value":1451},"*Skeleton",{"type":61,"value":1453}," colocated with the component;",{"type":56,"tag":118,"props":1455,"children":1456},{},[1457,1459,1464],{"type":61,"value":1458},"the fallback already inside the component's own ",{"type":56,"tag":69,"props":1460,"children":1462},{"className":1461},[],[1463],{"type":61,"value":388},{"type":61,"value":149},{"type":56,"tag":63,"props":1466,"children":1467},{},[1468,1470,1475,1477,1482,1484,1489,1491,1496],{"type":61,"value":1469},"The ",{"type":56,"tag":122,"props":1471,"children":1472},{},[1473],{"type":61,"value":1474},"divergence point",{"type":61,"value":1476}," is the lowest layout shared by the source and\ndestination routes: a soft navigation re-renders only the segments below it,\nwhile an initial load re-runs every layout from the root. (Also called the\nshared boundary.) A ",{"type":56,"tag":69,"props":1478,"children":1480},{"className":1479},[],[1481],{"type":61,"value":236},{"type":61,"value":1483}," above the divergence point fills only\nthe initial-load shell; it sits above the soft-nav re-render scope. A\n",{"type":56,"tag":69,"props":1485,"children":1487},{"className":1486},[],[1488],{"type":61,"value":236},{"type":61,"value":1490}," at the destination segment is itself the in-tree boundary for a\nsoft navigation into that segment and serves both. Reuse whichever boundary\nactually covers the navigation you are shipping; below the divergence point,\n",{"type":56,"tag":69,"props":1492,"children":1494},{"className":1493},[],[1495],{"type":61,"value":236},{"type":61,"value":1497}," and colocated skeletons are interchangeable for that purpose.",{"type":56,"tag":63,"props":1499,"children":1500},{},[1501],{"type":61,"value":1502},"If a component has no skeleton, extract its loading markup into a colocated\nskeleton beside it. Do not author a fresh skeleton that mirrors the page\nlayout: it duplicates structure, drifts as the page changes, and pulls the\ndesign back toward a single coarse boundary. Reusing the component's own\nskeleton also keeps the prefetched shell consistent with the loaded UI.",{"type":56,"tag":63,"props":1504,"children":1505},{},[1506,1508,1514,1516,1521],{"type":61,"value":1507},"Exception: if the deferred component renders ",{"type":56,"tag":69,"props":1509,"children":1511},{"className":1510},[],[1512],{"type":61,"value":1513},"null",{"type":61,"value":1515}," for some users (for\nexample, a flag-gated control), ",{"type":56,"tag":69,"props":1517,"children":1519},{"className":1518},[],[1520],{"type":61,"value":305},{"type":61,"value":1522}," is correct, since a skeleton\nwould flash and then collapse.",{"type":56,"tag":1116,"props":1524,"children":1526},{"id":1525},"d2-the-shell-must-match-the-real-render-at-every-breakpoint",[1527],{"type":61,"value":1528},"D2: the shell must match the real render at every breakpoint",{"type":56,"tag":63,"props":1530,"children":1531},{},[1532,1534,1540,1542,1548,1550,1555],{"type":61,"value":1533},"A skeleton frozen to one breakpoint misaligns on the others. Fix it the same\nway: one responsive component renders both the live UI and the shell (D1\nskeleton in its data slots), so the breakpoint switch happens once. Verify by\nre-asserting the shell marker at two widths\n(",{"type":56,"tag":69,"props":1535,"children":1537},{"className":1536},[],[1538],{"type":61,"value":1539},"await page.setViewportSize({ width: 1280, height: 800 })",{"type":61,"value":1541},", then\n",{"type":56,"tag":69,"props":1543,"children":1545},{"className":1544},[],[1546],{"type":61,"value":1547},"{ width: 390, height: 844 }",{"type":61,"value":1549},"), or by adding a mobile Playwright project, so\nthis gate is as machine-checkable as the others. Detail:\n",{"type":56,"tag":69,"props":1551,"children":1553},{"className":1552},[],[1554],{"type":61,"value":98},{"type":61,"value":149},{"type":56,"tag":1009,"props":1557,"children":1558},{},[1559],{"type":56,"tag":63,"props":1560,"children":1561},{},[1562,1567],{"type":56,"tag":122,"props":1563,"children":1564},{},[1565],{"type":61,"value":1566},"D-gate: phase D is complete when the locked test from phase C passes GREEN\nunder the lock on the production-build rig",{"type":61,"value":1568},", not when the code compiles. That\nGREEN is the deterministic stop for the fix loop; proceed to E.",{"type":56,"tag":63,"props":1570,"children":1571},{},[1572,1577,1579,1585,1586,1591,1593,1599,1601,1608,1610,1615,1617,1622],{"type":56,"tag":122,"props":1573,"children":1574},{},[1575],{"type":61,"value":1576},"When URL data can't be pushed down",{"type":61,"value":1578}," (for example, the whole page depends on\n",{"type":56,"tag":69,"props":1580,"children":1582},{"className":1581},[],[1583],{"type":61,"value":1584},"params",{"type":61,"value":1310},{"type":56,"tag":69,"props":1587,"children":1589},{"className":1588},[],[1590],{"type":61,"value":1293},{"type":61,"value":1592},", or the full URL), there may be no meaningful static\nshell to grow. Don't force one. Runtime prefetching can make the soft\nnavigation instant, but it is outside this optimizer loop: it requires Partial\nPrefetching, a ",{"type":56,"tag":69,"props":1594,"children":1596},{"className":1595},[],[1597],{"type":61,"value":1598},"\u003CLink prefetch={true}>",{"type":61,"value":1600},", and cached URL-dependent content. See\n",{"type":56,"tag":153,"props":1602,"children":1605},{"href":1603,"rel":1604},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fguides\u002Fruntime-prefetching",[157],[1606],{"type":61,"value":1607},"Runtime Prefetching",{"type":61,"value":1609},"\nand pattern 10 in ",{"type":56,"tag":69,"props":1611,"children":1613},{"className":1612},[],[1614],{"type":61,"value":90},{"type":61,"value":1616}," for the requirements, cost trade-offs,\nmanual prefetch caveat, and ",{"type":56,"tag":69,"props":1618,"children":1620},{"className":1619},[],[1621],{"type":61,"value":82},{"type":61,"value":1623}," test gotchas.",{"type":56,"tag":102,"props":1625,"children":1627},{"id":1626},"e-parity-the-refactor-changed-only-whether-the-route-is-instant",[1628],{"type":61,"value":1629},"E. PARITY: the refactor changed only whether the route is instant",{"type":56,"tag":63,"props":1631,"children":1632},{},[1633],{"type":61,"value":1634},"The push-down is a mechanical transform, not a redesign. Afterward the route\nmust render the same tree, data, ordering, empty and error states, redirects,\nand interactions as before; the only observable difference is that the shell\nnow commits instantly. Verify:",{"type":56,"tag":114,"props":1636,"children":1637},{},[1638,1655,1681,1691],{"type":56,"tag":118,"props":1639,"children":1640},{},[1641,1646,1648,1653],{"type":56,"tag":122,"props":1642,"children":1643},{},[1644],{"type":61,"value":1645},"Same render output.",{"type":61,"value":1647}," The moved ",{"type":56,"tag":69,"props":1649,"children":1651},{"className":1650},[],[1652],{"type":61,"value":1127},{"type":61,"value":1654},"s compute and return the same\nvalues; after the stream, the route shows the same content as the base\nbranch for the test user.",{"type":56,"tag":118,"props":1656,"children":1657},{},[1658,1663,1665,1671,1673,1679],{"type":56,"tag":122,"props":1659,"children":1660},{},[1661],{"type":61,"value":1662},"Side effects still fire.",{"type":61,"value":1664}," A deferred ",{"type":56,"tag":69,"props":1666,"children":1668},{"className":1667},[],[1669],{"type":61,"value":1670},"redirect()",{"type":61,"value":1672}," or ",{"type":56,"tag":69,"props":1674,"children":1676},{"className":1675},[],[1677],{"type":61,"value":1678},"notFound()",{"type":61,"value":1680}," still\nhappens, at request time rather than during prerender. Confirm an\nunauthorized user is still redirected and a missing record still returns 404.",{"type":56,"tag":118,"props":1682,"children":1683},{},[1684,1689],{"type":56,"tag":122,"props":1685,"children":1686},{},[1687],{"type":61,"value":1688},"Both viewports reach the real UI",{"type":61,"value":1690}," after the stream (D2).",{"type":56,"tag":118,"props":1692,"children":1693},{},[1694,1699],{"type":56,"tag":122,"props":1695,"children":1696},{},[1697],{"type":61,"value":1698},"Client state survives.",{"type":61,"value":1700}," Because the layout UI is hoisted into the stable\nshell rather than swapped on resolve, open menus, scroll position, focus,\nand input state persist across the stream.",{"type":56,"tag":63,"props":1702,"children":1703},{},[1704],{"type":61,"value":1705},"If anything other than whether the route is instant changed, reduce the refactor.",{"type":56,"tag":102,"props":1707,"children":1709},{"id":1708},"f-differential",[1710],{"type":61,"value":1711},"F. DIFFERENTIAL",{"type":56,"tag":63,"props":1713,"children":1714},{},[1715,1717,1722],{"type":61,"value":1716},"Revert only the fix → RED; re-apply → GREEN; link both runs\n(",{"type":56,"tag":69,"props":1718,"children":1720},{"className":1719},[],[1721],{"type":61,"value":726},{"type":61,"value":1723},"). On a deployed rig, confirm each run is live\n(LIVENESS, phase A) before trusting its color.",{"type":56,"tag":102,"props":1725,"children":1727},{"id":1726},"g-review-pr-checklist",[1728],{"type":61,"value":1729},"G. REVIEW (PR checklist)",{"type":56,"tag":63,"props":1731,"children":1732},{},[1733,1735,1740],{"type":61,"value":1734},"A green final state means nothing if the RED was never trustworthy. The\ntest-trustworthiness items are the robustness checklist\n(",{"type":56,"tag":69,"props":1736,"children":1738},{"className":1737},[],[1739],{"type":61,"value":726},{"type":61,"value":1741},"); confirm them, then require these\nPR-specific items:",{"type":56,"tag":114,"props":1743,"children":1746},{"className":1744},[1745],"contains-task-list",[1747,1766,1781,1796],{"type":56,"tag":118,"props":1748,"children":1751},{"className":1749},[1750],"task-list-item",[1752,1758,1759,1764],{"type":56,"tag":1753,"props":1754,"children":1757},"input",{"disabled":1755,"type":1756},true,"checkbox",[],{"type":61,"value":76},{"type":56,"tag":122,"props":1760,"children":1761},{},[1762],{"type":61,"value":1763},"Differential shown",{"type":61,"value":1765},": RED without the fix, GREEN with it, runs linked.",{"type":56,"tag":118,"props":1767,"children":1769},{"className":1768},[1750],[1770,1773,1774,1779],{"type":56,"tag":1753,"props":1771,"children":1772},{"disabled":1755,"type":1756},[],{"type":61,"value":76},{"type":56,"tag":122,"props":1775,"children":1776},{},[1777],{"type":61,"value":1778},"Parity confirmed (E)",{"type":61,"value":1780},": same content, redirects, and state.",{"type":56,"tag":118,"props":1782,"children":1784},{"className":1783},[1750],[1785,1788,1789,1794],{"type":56,"tag":1753,"props":1786,"children":1787},{"disabled":1755,"type":1756},[],{"type":61,"value":76},{"type":56,"tag":122,"props":1790,"children":1791},{},[1792],{"type":61,"value":1793},"Existing loading UI reused (D1)",{"type":61,"value":1795},": no new page-mirroring skeleton.",{"type":56,"tag":118,"props":1797,"children":1799},{"className":1798},[1750],[1800,1803,1804,1809],{"type":56,"tag":1753,"props":1801,"children":1802},{"disabled":1755,"type":1756},[],{"type":61,"value":76},{"type":56,"tag":122,"props":1805,"children":1806},{},[1807],{"type":61,"value":1808},"Shell matches the real render at desktop and mobile widths (D2)",{"type":61,"value":149},{"type":56,"tag":63,"props":1811,"children":1812},{},[1813,1818],{"type":56,"tag":122,"props":1814,"children":1815},{},[1816],{"type":61,"value":1817},"Stop condition for the whole workflow:",{"type":61,"value":1819}," the locked test from C is GREEN on\nthe rig, the differential (F) holds, and every item above is checked. Until all\nthree hold, you are not done.",{"type":56,"tag":102,"props":1821,"children":1823},{"id":1822},"driving-the-navigation-in-tests",[1824],{"type":61,"value":1825},"Driving the navigation in tests",{"type":56,"tag":114,"props":1827,"children":1828},{},[1829,1895],{"type":56,"tag":118,"props":1830,"children":1831},{},[1832,1837,1839,1844,1846,1851,1853,1859,1861,1866,1868,1873,1875,1881,1883,1888,1889,1894],{"type":56,"tag":122,"props":1833,"children":1834},{},[1835],{"type":61,"value":1836},"Soft navigation",{"type":61,"value":1838}," → drive a real ",{"type":56,"tag":69,"props":1840,"children":1842},{"className":1841},[],[1843],{"type":61,"value":254},{"type":61,"value":1845}," click. ",{"type":56,"tag":122,"props":1847,"children":1848},{},[1849],{"type":61,"value":1850},"Initial load",{"type":61,"value":1852}," → use\n",{"type":56,"tag":69,"props":1854,"children":1856},{"className":1855},[],[1857],{"type":61,"value":1858},"page.goto()",{"type":61,"value":1860}," inside ",{"type":56,"tag":69,"props":1862,"children":1864},{"className":1863},[],[1865],{"type":61,"value":82},{"type":61,"value":1867}," with the ",{"type":56,"tag":69,"props":1869,"children":1871},{"className":1870},[],[1872],{"type":61,"value":655},{"type":61,"value":1874}," option. Do not substitute\n",{"type":56,"tag":69,"props":1876,"children":1878},{"className":1877},[],[1879],{"type":61,"value":1880},"goto",{"type":61,"value":1882}," for a soft-nav verdict; the two shells can differ\n(",{"type":56,"tag":69,"props":1884,"children":1886},{"className":1885},[],[1887],{"type":61,"value":734},{"type":61,"value":1310},{"type":56,"tag":69,"props":1890,"children":1892},{"className":1891},[],[1893],{"type":61,"value":98},{"type":61,"value":238},{"type":56,"tag":118,"props":1896,"children":1897},{},[1898,1900,1905],{"type":61,"value":1899},"With parallel routes, only the slots that change re-render on a soft\nnavigation; client-rendered navigation UI does not re-render at all. Do not\nchase a slot the navigation never touches\n(",{"type":56,"tag":69,"props":1901,"children":1903},{"className":1902},[],[1904],{"type":61,"value":98},{"type":61,"value":238},{"type":56,"tag":102,"props":1907,"children":1909},{"id":1908},"files",[1910],{"type":61,"value":1911},"Files",{"type":56,"tag":114,"props":1913,"children":1914},{},[1915,1932,1949,1959],{"type":56,"tag":118,"props":1916,"children":1917},{},[1918,1923,1925,1930],{"type":56,"tag":69,"props":1919,"children":1921},{"className":1920},[],[1922],{"type":61,"value":636},{"type":61,"value":1924},": phase 0, the six-question rig discovery, the\n",{"type":56,"tag":69,"props":1926,"children":1928},{"className":1927},[],[1929],{"type":61,"value":625},{"type":61,"value":1931}," template, and filled examples (local-only, generic CI,\npreview deploy).",{"type":56,"tag":118,"props":1933,"children":1934},{},[1935,1940,1942,1947],{"type":56,"tag":69,"props":1936,"children":1938},{"className":1937},[],[1939],{"type":61,"value":734},{"type":61,"value":1941},": the shipped ",{"type":56,"tag":69,"props":1943,"children":1945},{"className":1944},[],[1946],{"type":61,"value":82},{"type":61,"value":1948}," specs for both navigation\ntypes (phase C), and the delete-before-PR baseline scaffold (phase B).",{"type":56,"tag":118,"props":1950,"children":1951},{},[1952,1957],{"type":56,"tag":69,"props":1953,"children":1955},{"className":1954},[],[1956],{"type":61,"value":726},{"type":61,"value":1958},": the C-gate and phase F. The taxonomy of\nuntrustworthy REDs, the checklist, the differential recipe, the vacuous-pass\nfailure mode, and worked cases.",{"type":56,"tag":118,"props":1960,"children":1961},{},[1962,1967],{"type":56,"tag":69,"props":1963,"children":1965},{"className":1964},[],[1966],{"type":61,"value":98},{"type":61,"value":1968},": parallel routes, deferring an auth gate,\ninitial-load vs soft-navigation shells, the empty-shell failure mode, the\nresponsive-skeleton mismatch, edge cases.",{"type":56,"tag":102,"props":1970,"children":1972},{"id":1971},"after-optimization",[1973],{"type":61,"value":1974},"After optimization",{"type":56,"tag":63,"props":1976,"children":1977},{},[1978,1980,1986,1988,1994],{"type":61,"value":1979},"Once the target routes are instant, check whether the app has already adopted\nPartial Prefetching (",{"type":56,"tag":69,"props":1981,"children":1983},{"className":1982},[],[1984],{"type":61,"value":1985},"partialPrefetching: true",{"type":61,"value":1987},", or the relevant destination\nstill uses ",{"type":56,"tag":69,"props":1989,"children":1991},{"className":1990},[],[1992],{"type":61,"value":1993},"prefetch = 'partial'",{"type":61,"value":1995}," during an incremental rollout).",{"type":56,"tag":63,"props":1997,"children":1998},{},[1999],{"type":61,"value":2000},"Make that check mechanically:",{"type":56,"tag":405,"props":2002,"children":2006},{"className":2003,"code":2004,"language":2005,"meta":413,"style":413},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","rg -n \"partialPrefetching|prefetch\\s*=\\s*['\\\"]partial['\\\"]\" --glob 'next.config.*' --glob 'app\u002F**' --glob 'src\u002Fapp\u002F**'\n","bash",[2007],{"type":56,"tag":69,"props":2008,"children":2009},{"__ignoreMap":413},[2010],{"type":56,"tag":543,"props":2011,"children":2012},{"class":545,"line":546},[2013,2018,2023,2028,2033,2038,2043,2047,2052,2057,2062,2066,2071,2075,2079,2083,2088,2092,2096,2100,2105],{"type":56,"tag":543,"props":2014,"children":2015},{"style":756},[2016],{"type":61,"value":2017},"rg",{"type":56,"tag":543,"props":2019,"children":2020},{"style":860},[2021],{"type":61,"value":2022}," -n",{"type":56,"tag":543,"props":2024,"children":2025},{"style":561},[2026],{"type":61,"value":2027}," \"",{"type":56,"tag":543,"props":2029,"children":2030},{"style":860},[2031],{"type":61,"value":2032},"partialPrefetching|prefetch\\s*=\\s*['",{"type":56,"tag":543,"props":2034,"children":2035},{"style":826},[2036],{"type":61,"value":2037},"\\\"",{"type":56,"tag":543,"props":2039,"children":2040},{"style":860},[2041],{"type":61,"value":2042},"]partial['",{"type":56,"tag":543,"props":2044,"children":2045},{"style":826},[2046],{"type":61,"value":2037},{"type":56,"tag":543,"props":2048,"children":2049},{"style":860},[2050],{"type":61,"value":2051},"]",{"type":56,"tag":543,"props":2053,"children":2054},{"style":561},[2055],{"type":61,"value":2056},"\"",{"type":56,"tag":543,"props":2058,"children":2059},{"style":860},[2060],{"type":61,"value":2061}," --glob",{"type":56,"tag":543,"props":2063,"children":2064},{"style":561},[2065],{"type":61,"value":857},{"type":56,"tag":543,"props":2067,"children":2068},{"style":860},[2069],{"type":61,"value":2070},"next.config.*",{"type":56,"tag":543,"props":2072,"children":2073},{"style":561},[2074],{"type":61,"value":868},{"type":56,"tag":543,"props":2076,"children":2077},{"style":860},[2078],{"type":61,"value":2061},{"type":56,"tag":543,"props":2080,"children":2081},{"style":561},[2082],{"type":61,"value":857},{"type":56,"tag":543,"props":2084,"children":2085},{"style":860},[2086],{"type":61,"value":2087},"app\u002F**",{"type":56,"tag":543,"props":2089,"children":2090},{"style":561},[2091],{"type":61,"value":868},{"type":56,"tag":543,"props":2093,"children":2094},{"style":860},[2095],{"type":61,"value":2061},{"type":56,"tag":543,"props":2097,"children":2098},{"style":561},[2099],{"type":61,"value":857},{"type":56,"tag":543,"props":2101,"children":2102},{"style":860},[2103],{"type":61,"value":2104},"src\u002Fapp\u002F**",{"type":56,"tag":543,"props":2106,"children":2107},{"style":561},[2108],{"type":61,"value":2109},"'\n",{"type":56,"tag":63,"props":2111,"children":2112},{},[2113,2115,2120,2122,2127],{"type":61,"value":2114},"If ",{"type":56,"tag":69,"props":2116,"children":2118},{"className":2117},[],[2119],{"type":61,"value":1985},{"type":61,"value":2121}," is in config, the app is globally adopted. If only\n",{"type":56,"tag":69,"props":2123,"children":2125},{"className":2124},[],[2126],{"type":61,"value":1993},{"type":61,"value":2128}," matches, treat those destination segments as adopted\nduring an incremental rollout and keep checking any other target routes.",{"type":56,"tag":114,"props":2130,"children":2131},{},[2132,2149],{"type":56,"tag":118,"props":2133,"children":2134},{},[2135,2140,2142,2147],{"type":56,"tag":122,"props":2136,"children":2137},{},[2138],{"type":61,"value":2139},"Already adopted:",{"type":61,"value":2141}," for any URL-data route that stopped at the limitation\nabove, consider a targeted ",{"type":56,"tag":69,"props":2143,"children":2145},{"className":2144},[],[2146],{"type":61,"value":1598},{"type":61,"value":2148}," on the links where having\nthat URL-specific content ready before the click is worth the per-link server\nwork. Keep the default link behavior everywhere else so the shared App Shell\nremains the low-cost baseline.",{"type":56,"tag":118,"props":2150,"children":2151},{},[2152,2157,2159,2170,2172,2177],{"type":56,"tag":122,"props":2153,"children":2154},{},[2155],{"type":61,"value":2156},"Not adopted yet:",{"type":61,"value":2158}," recommend\n",{"type":56,"tag":153,"props":2160,"children":2163},{"href":2161,"rel":2162},"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fnext.js\u002Ftree\u002Fcanary\u002Fskills\u002Fnext-partial-prefetching-adoption",[157],[2164],{"type":56,"tag":69,"props":2165,"children":2167},{"className":2166},[],[2168],{"type":61,"value":2169},"next-partial-prefetching-adoption",{"type":61,"value":2171},".\nThat skill moves the app onto the better prefetching model: shared App Shell\nprefetches by default, fewer duplicated full-prefetch requests for visible\nlinks, a link audit for existing ",{"type":56,"tag":69,"props":2173,"children":2175},{"className":2174},[],[2176],{"type":61,"value":1598},{"type":61,"value":2178}," usage, and optional\nper-link runtime prefetching only where URL-specific content is worth the\nextra server work.",{"type":56,"tag":2180,"props":2181,"children":2182},"style",{},[2183],{"type":61,"value":2184},"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":2186,"total":790},[2187,2200,2208,2227],{"slug":601,"name":601,"fn":2188,"description":2189,"org":2190,"tags":2191,"stars":26,"repoUrl":27,"updatedAt":2199},"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},[2192,2193,2194,2197,2198],{"name":21,"slug":22,"type":15},{"name":24,"slug":25,"type":15},{"name":2195,"slug":2196,"type":15},"Migration","migration",{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},"2026-07-24T05:38:30.118542",{"slug":4,"name":4,"fn":5,"description":6,"org":2201,"tags":2202,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2203,2204,2205,2206,2207],{"name":21,"slug":22,"type":15},{"name":24,"slug":25,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":2209,"name":2209,"fn":2210,"description":2211,"org":2212,"tags":2213,"stars":26,"repoUrl":27,"updatedAt":2226},"next-dev-loop","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},[2214,2217,2218,2221,2222,2223],{"name":2215,"slug":2216,"type":15},"Debugging","debugging",{"name":24,"slug":25,"type":15},{"name":2219,"slug":2220,"type":15},"Local Development","local-development",{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":2224,"slug":2225,"type":15},"Web Development","web-development","2026-05-22T06:45:28.627735",{"slug":2169,"name":2169,"fn":2228,"description":2229,"org":2230,"tags":2231,"stars":26,"repoUrl":27,"updatedAt":2236},"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},[2232,2233,2234,2235],{"name":24,"slug":25,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-07-30T05:31:11.591864",{"items":2238,"total":2383},[2239,2247,2255,2264,2271,2286,2302,2320,2332,2351,2363,2373],{"slug":601,"name":601,"fn":2188,"description":2189,"org":2240,"tags":2241,"stars":26,"repoUrl":27,"updatedAt":2199},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2242,2243,2244,2245,2246],{"name":21,"slug":22,"type":15},{"name":24,"slug":25,"type":15},{"name":2195,"slug":2196,"type":15},{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"slug":4,"name":4,"fn":5,"description":6,"org":2248,"tags":2249,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2250,2251,2252,2253,2254],{"name":21,"slug":22,"type":15},{"name":24,"slug":25,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":2209,"name":2209,"fn":2210,"description":2211,"org":2256,"tags":2257,"stars":26,"repoUrl":27,"updatedAt":2226},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2258,2259,2260,2261,2262,2263],{"name":2215,"slug":2216,"type":15},{"name":24,"slug":25,"type":15},{"name":2219,"slug":2220,"type":15},{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":2224,"slug":2225,"type":15},{"slug":2169,"name":2169,"fn":2228,"description":2229,"org":2265,"tags":2266,"stars":26,"repoUrl":27,"updatedAt":2236},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2267,2268,2269,2270],{"name":24,"slug":25,"type":15},{"name":18,"slug":19,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":2272,"name":2272,"fn":2273,"description":2274,"org":2275,"tags":2276,"stars":2283,"repoUrl":2284,"updatedAt":2285},"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},[2277,2280,2281],{"name":2278,"slug":2279,"type":15},"CI\u002FCD","ci-cd",{"name":13,"slug":14,"type":15},{"name":2282,"slug":2272,"type":15},"Turborepo",30809,"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fturborepo","2026-07-30T05:32:14.920116",{"slug":2287,"name":2287,"fn":2288,"description":2289,"org":2290,"tags":2291,"stars":2299,"repoUrl":2300,"updatedAt":2301},"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},[2292,2295,2298],{"name":2293,"slug":2294,"type":15},"AI SDK","ai-sdk",{"name":2296,"slug":2297,"type":15},"Testing","testing",{"name":9,"slug":8,"type":15},25670,"https:\u002F\u002Fgithub.com\u002Fvercel\u002Fai","2026-04-06T18:55:51.318866",{"slug":2303,"name":2303,"fn":2304,"description":2305,"org":2306,"tags":2307,"stars":2299,"repoUrl":2300,"updatedAt":2319},"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},[2308,2311,2312,2315,2318],{"name":2309,"slug":2310,"type":15},"Agents","agents",{"name":2293,"slug":2294,"type":15},{"name":2313,"slug":2314,"type":15},"Harness","harness",{"name":2316,"slug":2317,"type":15},"SDK","sdk",{"name":9,"slug":8,"type":15},"2026-06-18T08:29:19.858737",{"slug":2321,"name":2321,"fn":2322,"description":2323,"org":2324,"tags":2325,"stars":2299,"repoUrl":2300,"updatedAt":2331},"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},[2326,2327,2330],{"name":2293,"slug":2294,"type":15},{"name":2328,"slug":2329,"type":15},"API Development","api-development",{"name":9,"slug":8,"type":15},"2026-04-06T18:55:47.45549",{"slug":2333,"name":2333,"fn":2334,"description":2335,"org":2336,"tags":2337,"stars":2299,"repoUrl":2300,"updatedAt":2350},"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},[2338,2341,2344,2347],{"name":2339,"slug":2340,"type":15},"ADR","adr",{"name":2342,"slug":2343,"type":15},"Architecture","architecture",{"name":2345,"slug":2346,"type":15},"Documentation","documentation",{"name":2348,"slug":2349,"type":15},"Engineering","engineering","2026-04-06T18:55:50.043694",{"slug":2294,"name":2294,"fn":2352,"description":2353,"org":2354,"tags":2355,"stars":2299,"repoUrl":2300,"updatedAt":2362},"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},[2356,2357,2358,2361],{"name":2309,"slug":2310,"type":15},{"name":2293,"slug":2294,"type":15},{"name":2359,"slug":2360,"type":15},"LLM","llm",{"name":9,"slug":8,"type":15},"2026-04-06T18:55:48.739463",{"slug":2364,"name":2364,"fn":2365,"description":2366,"org":2367,"tags":2368,"stars":2299,"repoUrl":2300,"updatedAt":2372},"capture-api-response-test-fixture","capture API response test fixtures","Capture API response test fixture.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2369,2370,2371],{"name":2328,"slug":2329,"type":15},{"name":2296,"slug":2297,"type":15},{"name":9,"slug":8,"type":15},"2026-04-06T18:55:56.374433",{"slug":2374,"name":2374,"fn":2375,"description":2376,"org":2377,"tags":2378,"stars":2299,"repoUrl":2300,"updatedAt":2382},"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},[2379,2380,2381],{"name":2293,"slug":2294,"type":15},{"name":2296,"slug":2297,"type":15},{"name":9,"slug":8,"type":15},"2026-04-06T18:55:55.088956",68]