mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
dev-overlay: wire Link prefetch={true} Partial Prefetching warning into Insights (#94798)
### What?
Wires the dev-only `<Link prefetch={true}>` Partial Prefetching warning
from [#94672](https://github.com/vercel/next.js/pull/94672) into the
Instant Insights surface. Code frame, call stack, three fix cards:
**Upgrade** `prefetch = 'partial'` · **Disable** the prop · **Ignore**
with `instant = false`.
Demo:
[93-link-prefetch-without-partial](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/93-link-prefetch-without-partial).
### How?
- Warning factored into a shared `instant-messages.ts` factory.
- New `link-prefetch-partial` overlay kind + `Instant` label +
`InstantRuntimeError` dispatcher.
- Two new fix-card groups: **Upgrade** (amber, arrow-up), **Disable**
(gray, minus).
- New `instant-link-prefetch-partial.mdx` rule page + "Auditing existing
calls" section in the adoption guide.
- Unit tests for the matcher, cards, and `isInstantNavigationError`.
### Related
- [#94818](https://github.com/vercel/next.js/pull/94818) — broader
Partial Prefetching docs cleanup. Lands independently.
- [vercel/front#73592](https://github.com/vercel/front/pull/73592) —
next-site `upgrade` + `disable` `FixGroup` values.
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: Next.js encountered dynamic data during prefetching
|
||||
kind: insight
|
||||
---
|
||||
|
||||
During a [client-side navigation](/docs/app/glossary#client-side-navigation), a [`<Link prefetch={true}>`](/docs/app/api-reference/components/link) navigated to a route that has not enabled [Partial Prefetching](/docs/app/glossary#partial-prefetching). With [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents) enabled, `prefetch={true}` is a legacy "full" prefetch that pulls down the route's dynamic data along with its [App Shell](/docs/app/glossary#app-shell). This will lead to slower, more expensive prefetches.
|
||||
|
||||
Routes that opt into Partial Prefetching skip the dynamic data at prefetch time, leaving you free to choose when it loads: at navigation via [streaming](/docs/app/glossary#streaming), ahead of time via [runtime prefetching](/docs/app/guides/runtime-prefetching), or not at all. The check fires at navigation time, not prefetch time, so existing apps that have just enabled Cache Components are not flooded with warnings for every `<Link prefetch={true}>` on the page.
|
||||
|
||||
> **Good to know**: In [`next dev`](/docs/app/api-reference/cli/next#next-dev-options), the error overlay points at the failing component. Run `next build --debug-prerender` to get the full list of blocking routes with stack traces. When iterating on specific routes, use `next build --debug-build-paths /dashboard /settings` to rebuild only those pages.
|
||||
|
||||
## Ways to fix this
|
||||
|
||||
<FixOption
|
||||
group="upgrade"
|
||||
href="#opt-into-partial-prefetching"
|
||||
title="Opt into Partial Prefetching"
|
||||
>
|
||||
Adopt Partial Prefetching for the target route so the link prefetches only the
|
||||
App Shell. After adopting, layer on further prefetch optimizations.
|
||||
</FixOption>
|
||||
|
||||
<FixOption
|
||||
group="disable"
|
||||
href="#use-the-default-prefetch"
|
||||
title="Use the default prefetch"
|
||||
>
|
||||
Drop the prefetch prop from the link so it falls back to the default prefetch
|
||||
behavior, which does not include dynamic data.
|
||||
</FixOption>
|
||||
|
||||
<FixOption
|
||||
group="ignore"
|
||||
href="#disable-validation-on-this-route"
|
||||
title="Disable validation on this route"
|
||||
>
|
||||
Opt the target route out of instant-navigation validation and keep the legacy
|
||||
full prefetch.
|
||||
</FixOption>
|
||||
|
||||
## Opt into Partial Prefetching
|
||||
|
||||
Choose this fix when the target route has an [App Shell](/docs/app/glossary#app-shell) with dynamic content below it. Opting into Partial Prefetching tells Next.js to prefetch only the App Shell and defer the dynamic data to navigation. Opt in per-route or app-wide, and from there layer on further prefetch optimizations.
|
||||
|
||||
### Patterns
|
||||
|
||||
#### Per-route opt-in
|
||||
|
||||
Export [`prefetch`](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) from the page or layout of the route the link points at.
|
||||
|
||||
```jsx filename="app/dashboard/page.js"
|
||||
export const prefetch = 'partial'
|
||||
|
||||
export default function DashboardPage() {
|
||||
return <Dashboard />
|
||||
}
|
||||
```
|
||||
|
||||
#### App-wide opt-in
|
||||
|
||||
Set [`partialPrefetching`](/docs/app/api-reference/config/next-config-js/partialPrefetching) to `true` in `next.config` to opt the whole app in.
|
||||
|
||||
```js filename="next.config.js"
|
||||
module.exports = {
|
||||
partialPrefetching: true,
|
||||
}
|
||||
```
|
||||
|
||||
Learn more: [Adopting Partial Prefetching](/docs/app/guides/adopting-partial-prefetching).
|
||||
|
||||
### Trade-off
|
||||
|
||||
The route's dynamic data isn't included in the prefetch. The user sees the App Shell as soon as the link enters the viewport, and the dynamic content streams in after navigation. The dynamic content arrives later than it would with a full prefetch. How much later depends on how long the dynamic data takes to fetch.
|
||||
|
||||
### Gotchas
|
||||
|
||||
- Partial Prefetching only works with [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents) enabled.
|
||||
- If the route doesn't have a clear App Shell (everything below the layout reads dynamic data), Partial Prefetching has nothing to prefetch and behaves the same as no prefetch. Move static content above the dynamic boundary first.
|
||||
|
||||
### Next steps
|
||||
|
||||
Opting in stops at the App Shell. To also prefetch cached parts of the route, set `prefetch={true}` on the link. If the cached content depends on request data (cookies, headers, search params), opt the route into [runtime prefetching](/docs/app/guides/runtime-prefetching). The [prefetching guide](/docs/app/guides/prefetching) covers the link-level options end to end.
|
||||
|
||||
## Use the default prefetch
|
||||
|
||||
Choose this fix when you set `prefetch={true}` to warm up a frequently-visited route and you can accept fetching the dynamic data on navigation. Remove the prop and the link uses the default prefetch strategy, which under Cache Components prefetches the cached page render and skips the dynamic data.
|
||||
|
||||
### Patterns
|
||||
|
||||
#### Remove the `prefetch` prop
|
||||
|
||||
```jsx filename="app/nav.js"
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function Nav() {
|
||||
return <Link href="/dashboard">Dashboard</Link>
|
||||
}
|
||||
```
|
||||
|
||||
### Trade-off
|
||||
|
||||
The link no longer forces a full prefetch. The user gets the cached parts of the route when the link enters the viewport, and the dynamic data is fetched at navigation time. This is the default behavior under Cache Components.
|
||||
|
||||
### Gotchas
|
||||
|
||||
- Removing `prefetch={true}` does not disable prefetching. It falls back to the default. To disable prefetching entirely, use `prefetch={false}`.
|
||||
- See [Adopting Partial Prefetching](/docs/app/guides/adopting-partial-prefetching) for the full table of what each `<Link>` prop downloads under each configuration.
|
||||
|
||||
## Disable validation on this route
|
||||
|
||||
Choose this fix when you need the legacy full prefetch behavior and cannot adopt Partial Prefetching for the target route. Setting [`instant`](/docs/app/api-reference/file-conventions/route-segment-config/instant) to `false` on the target route opts it out of instant-navigation validation and silences the warning.
|
||||
|
||||
### Patterns
|
||||
|
||||
#### Opt the route out
|
||||
|
||||
Add the export to the page or layout file of the target route.
|
||||
|
||||
```jsx filename="app/dashboard/page.js"
|
||||
export const instant = false
|
||||
|
||||
export default function DashboardPage() {
|
||||
return <Dashboard />
|
||||
}
|
||||
```
|
||||
|
||||
### Trade-off
|
||||
|
||||
The link continues to do a full prefetch, including dynamic data, and the warning is silenced.
|
||||
|
||||
### Gotchas
|
||||
|
||||
- `instant = false` disables all instant-navigation checks for the route, not only this one. [Blocking-route](/docs/messages/blocking-prerender-runtime) and [unrendered-segment](/docs/messages/instant-unrendered-segment) warnings, and other Insights for the route are silenced too.
|
||||
|
||||
## Don't want this validation?
|
||||
|
||||
Instant-navigation validation runs by default in [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents) apps and surfaces this error.
|
||||
|
||||
- **One segment**: add [`export const instant = false`](/docs/app/api-reference/file-conventions/route-segment-config/instant) to the page or layout file. This opts out the segment itself. Child segments are still validated during client navigations.
|
||||
- **Entire app**: set [`experimental.instantInsights.validationLevel`](/docs/app/api-reference/file-conventions/route-segment-config/instant#configuring-validation-defaults) to `'manual-warning'` in `next.config`. This limits validation to segments that explicitly export `instant`.
|
||||
|
||||
See [Ensuring instant navigations](/docs/app/guides/instant-navigation) for the full model.
|
||||
|
||||
## Useful links
|
||||
|
||||
- [Adopting Partial Prefetching](/docs/app/guides/adopting-partial-prefetching)
|
||||
- [Ensuring instant navigations](/docs/app/guides/instant-navigation)
|
||||
Reference in New Issue
Block a user