Repository navigation
docs(skills): preserve prefetched UI during Partial Prefetching adoption - #97712
Conversation
Tests PassedCommit: 36bb6bf |
Stats from current PR✅ No significant changes detected📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles
Server Middleware
Build DetailsBuild Manifests
Build Cache
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📎 Tarball URLCommit: a907b8b |
6b78989 to
5a115ac
Compare
6866e13 to
fc3c6d6
Compare
fc3c6d6 to
db4ca3a
Compare
| | [Reads URL data, or has cached content that depends on it](#url-data) | Keep `prefetch={true}` to resolve the content ahead of the click. | | ||
| | [Delivers real-time content that must stay fresh per request](#real-time-content) | Remove `prefetch={true}` and let the content stream in. | | ||
|
|
||
| ### Verify prefetched UI with tests |
There was a problem hiding this comment.
Maybe a nit but the table above is a summary of the sections that follow — should it be placed at the end of this run
After, Real-time content, and before Adopting incrementally
|
|
||
| For larger migrations, you can [adopt incrementally](#adopting-incrementally) with the global flag off. The [dynamic data during prefetching](/docs/messages/instant-link-prefetch-partial) insight identifies each destination that still uses the legacy full prefetch. | ||
|
|
||
| Both insights are development-only and never block the build. They appear in the dev overlay with fix cards that link the docs page for each fix. If a route isn't ready to adopt, export [`instant = false`](/docs/app/api-reference/file-conventions/route-segment-config/instant) from its page or layout to opt the route out of instant-navigation validation, and return to it later. |
There was a problem hiding this comment.
Item 1 used to end with
guided by the dynamic data during prefetching insight.
And item 2 still ends with:
resolving the URL data outside of Suspense insight.
And then it was an OK flow with Both insights — with this format, the list ends, and we talk about larger migrations, and an insight, and then we follow with 49, as a reader I may not connect to the insight on item 2.
Maybe a nit, but it feels a bit disconnected. I guess, item 2 is doing too much now?
|
|
||
| ## Enable Partial Prefetching | ||
|
|
||
| > **Good to know**: In an existing app, review the UI delivered by [`<Link prefetch={true}>`](#migrate-existing-full-prefetches) before enabling Partial Prefetching. This is the legacy full prefetch that the migration may change. |
There was a problem hiding this comment.
This is the legacy full prefetch that the migration may change
Should be?
Those links use the legacy full prefetch, which change their behavior when Partial Prefetching is enabled.
| ``` | ||
|
|
||
| After enabling the flag, every `<Link>` prefetches its destination's App Shell, and `<Link prefetch={true}>` no longer includes the route's dynamic content. Audit those links next to preserve what they delivered. A new project has no legacy links to audit and is done here. | ||
| After enabling the flag, every `<Link>` prefetches its destination's App Shell. A link with `prefetch={true}` can also resolve cached URL-specific content, but it no longer includes uncached dynamic content from the legacy full prefetch. This migration step doesn't apply to new projects. |
There was a problem hiding this comment.
This migration step doesn't apply to new project
Nit, but we haven't mentioned (in prose) migration just yet. And a new project doesn't need to migrate either, just adopt.
This doesn't apply to new projects.
But it feels incomplete like that too
…ion (#97712) ## What - Documents how legacy `prefetch={true}` behavior changes with Partial Prefetching and how to choose the UI worth preserving. - Updates the adoption skill to capture a passing flag-off `instant()` baseline, use the same assertions to drive the migration, and retain them as regression coverage. - Adds a reusable production test rig, keeps additional per-link optimization separate from adoption, and surfaces `prefetch={false}` links that may no longer be needed. - Applies the shared test-rig fixes discovered during dogfooding to the Cache Components optimizer. ## Why Legacy `prefetch={true}` could include uncached dynamic content. With Partial Prefetching, it includes the shared App Shell and cached URL-specific content instead. A passing build or clean insight sweep does not prove that the intended prefetched UI survived the migration, so the skill now records that contract before adoption and verifies it unchanged afterward. The guide presents the same test workflow as an optional programmatic check for manual adopters. ## Testing - Prettier, Alex, and skill frontmatter validation - Dogfooded on v0 in vercel/v0#28842 - Partial Prefetching adoption eval: 6/6 in #97759 (cherry picked from commit 24ed66a)
- docs: explain origin matching for allowedOrigins and allowedDevOrigins (#97805) - docs: improve discovery summaries (#97982) - docs(skills): preserve prefetched UI during Partial Prefetching adoption (#97712) - docs: add layout stability guidance for videos and iframes (#98070) - docs: document preloading with Cache Components (#97864) - docs: note that experimental.taint taints process.env (#98145) - docs: add API reference pages for skipProxyUrlNormalize and skipTrailingSlashRedirect (#97967) - docs: keep generateStaticParams during Cache Components migration (docs part of #98209) - docs: Remove version label from Turbopack in Pages Router (#98316) --------- Co-authored-by: Rich Haines <hello@richardhaines.dev> Co-authored-by: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com>
## Summary - add a Partial Prefetching optimizer Skill for selected source Links and destinations - keep prefetch stages and Link policy in the public [Optimizing prefetching guide](https://nextjs.org/docs/app/guides/optimizing-prefetching), and rely on the same static-shell documentation as the Cache Components optimizer for cache placement, Suspense, loading UI, and authorization - keep the Skill focused on the product decision, production `instant()` loop, differential verification, and mutation freshness when an optimization adds a cache around mutable data - reference the canonical [`unstable_prefetch()`](https://nextjs.org/docs/app/api-reference/functions/prefetch) and [`unstable_navigation()`](https://nextjs.org/docs/app/api-reference/functions/navigation) docs instead of explaining the APIs again in the Skill - link cache-writing optimizations to the canonical [Revalidating](https://nextjs.org/docs/app/getting-started/caching-and-revalidating#revalidating) documentation and verify a populated-cache mutation in the Skill and eval - bundle a self-contained production rig aligned with the related adoption and optimizer Skills, tuned to record each source-link and prefetch-stage contract - add an eval that compares baseline, the bundled guide, and the local Skill against the same prefetched-UI and cache-freshness goal - document the optimizer in the AI agents guide This follows the same guide/Skill split as #97737. Partial Prefetching adoption preserves existing behavior; this optimizer is the later decision about what is worth preparing before a click and what should wait for navigation. Related: #97712, #97737, #97759, #98122, #98175 ## Eval One run per treatment with Claude Opus 4.8 and Claude Sonnet 4.5, using a fixed Claude Haiku 4.5 judge. The bundled-guide and Skill treatments use a local Next.js tarball containing the new guide and API references. | Model | Treatment | Criteria | Score change | Overall | Duration | Tokens processed | Total run cost | Cost change | | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | Opus 4.8 | Baseline | 10/10 (100%) | — | Pass | 18m 42s | 3.39M | $3.46 | — | | Opus 4.8 | Bundled guide | 9/10 (90%) | -10 pp | Fail | 13m 37s | 3.02M | $2.84 | -18.0% | | Opus 4.8 | Local Skill | 10/10 (100%) | +10 pp | Pass | 17m 22s | 2.80M | $2.54 | -10.6% | | Sonnet 4.5 | Baseline | 2/10 (20%) | — | Fail | 15m 55s | 1.97M | $1.06 | — | | Sonnet 4.5 | Bundled guide | 5/10 (50%) | +30 pp | Fail | 15m 49s | 2.17M | $1.11 | +4.5% | | Sonnet 4.5 | Local Skill | 8/10 (80%) | +30 pp | Fail | 15m 31s | 1.41M | $0.77 | -30.4% | Token totals count each unique model message once and include uncached input, cache creation, cache reads, and output. Cache reads account for most of the total in every treatment. Total run cost applies the current AI Gateway base rates to each token category: Opus 4.8 costs $5/M input, $6.25/M cache writes, $0.50/M cache reads, and $25/M output; Sonnet 4.5 costs $3/M input, $3.75/M cache writes, $0.30/M cache reads, and $15/M output. The six agent runs cost $11.78 in total. Compared with baseline, the Opus Skill run maintained a 100% criteria pass rate while reducing cost by 26.7%. The Sonnet Skill run improved the criteria pass rate from 20% to 80%, a 60 percentage-point increase, while reducing cost by 27.3%. The stronger model could solve the fixture without the Skill, although it independently searched the bundled Next.js documentation and took slightly longer than the Skill treatment. The Opus guide-only run implemented the correct behavior but missed the required RED-before-GREEN proof. The Sonnet treatments show a clearer progression. Baseline did not implement the required caching, navigation stage, `instant()` contract, or cache invalidation. The bundled guide added the cached summary and production test, but missed the navigation stage, deferred-state assertions, tag invalidation, and RED-before-GREEN proof. The Skill treatment completed the `instant()` RED-to-GREEN loop and final production behavior, but left `connection()` in the related-sessions read and used path revalidation instead of tagging the cached read. It therefore passed 8 of 10 criteria but failed the overall eval. All six measured runs completed through grading. Chromium and its system dependencies are provisioned before the agent starts, so missing browser libraries did not determine these results. ## Verification - `pnpm --filter=next build` - `pnpm prettier --check` for the changed guide, prompt, Skill, and eval fixture - `pnpm exec tsc -p evals/evals/agent-051-optimize-partial-prefetching/tsconfig.json --noEmit` - `node --check run-evals.js` - `git diff --check` - packed a local Next.js tarball and confirmed it contains the optimizer guide plus the `navigation()` and `prefetch()` references - verified the `navigation()` contract in the minimal reproduction and NextBeats on Next.js 16.4.0-canary.22 - merged the latest `canary`, preserving both generic fixture setup and Playwright provisioning <!-- NEXT_JS_LLM -->
What
prefetch={true}behavior changes with Partial Prefetching and how to choose the UI worth preserving.instant()baseline, use the same assertions to drive the migration, and retain them as regression coverage.prefetch={false}links that may no longer be needed.Why
Legacy
prefetch={true}could include uncached dynamic content. With Partial Prefetching, it includes the shared App Shell and cached URL-specific content instead. A passing build or clean insight sweep does not prove that the intended prefetched UI survived the migration, so the skill now records that contract before adoption and verifies it unchanged afterward. The guide presents the same test workflow as an optional programmatic check for manual adopters.Testing