Skip to content
instant.by-design
L0410 min

What prefetch={true} means now

The old full-route prefetch is gone. What a default link warms now, the redefined prefetch={true}, the segment cost ceiling, and the silent regression to watch for.

The prefetch you remember no longer exists

Under the old model a visible <Link> prefetched the whole destination: the static parts fully, the dynamic parts up to the nearest loading boundary. Partial Prefetching redefines both the default and the prefetch={true} prop, and the change is easy to miss because nothing errors.

Two redefinitions

Default link: now warms only the shared App Shell (the static and session output the route shares), not the whole page.

prefetch={true}: no longer "prefetch everything." It now means "additionally resolve this link's URL data (params, searchParams) before the click."

1

Turn it on

partialPrefetching builds on cacheComponents; enable them together. The shell you structured in Lesson 3 is exactly what a link now prefetches by default, with no prop.

next.config.tstsx
// next.config.tsconst nextConfig: NextConfig = {  cacheComponents: true,  partialPrefetching: true,   // depends on cacheComponents}
2

The regression to watch for

If a page relied on the old full prefetch, so its per-URL content was ready on the click, a default link now delivers only the App Shell and that content streams in after the click instead. It still works, it is just slower than before, with no warning.

Default vs prefetch={true}tsx
// Default link: warms only the shared App Shell (cheap, one per route).<Link href="/dashboard">Dashboard</Link> // prefetch={true}: NOT "prefetch everything" anymore.// It means "also resolve THIS link's URL data before the click".<Link href={`/posts/${slug}`} prefetch={true}>{title}</Link>
Predict first

A link points to /posts/hello-world. The post body is cached but keyed by the slug. Does a default link prefetch the body?

Imperative prefetch has no safety net

router.prefetch() call sites do not surface a dev insight, so a preserved "fetch before navigate" behavior can silently degrade to shell-only. Audit those by hand and verify them under next start (prefetching is production-only).

3

Two dials: intent on the link, cost ceiling on the route

A prefetch has two independent controls. The <Link> prop states intent: should this be prefetched, how eagerly. The prefetch export on the destination sets a cost ceiling: how much any link may pull for this route. A destination cannot know which links point at it, so it caps the work.

app/posts/[slug]/page.tsxtsx
// app/posts/[slug]/page.tsx  — set on the DESTINATION, not the linkexport const prefetch = 'partial'   // adopt one route without the global flag
The prefetch segment config (on the destination)
ValueMeaning
'auto'The default; same as omitting it. Do not write it out explicitly.
'partial'Adopt one route into Partial Prefetching without the global flag. Default link → App Shell; a prefetch={true} link also resolves URL data.
'force-disabled'Never prefetch this segment. For rarely visited pages, e.g. behind auth.
force-disabled is leakier than it sounds

It does not stop route metadata from being prefetched. And if a parent segment runs a per-link prefetch, deeper segments are included in that same request, even ones marked force-disabled. It caps the segment's own default prefetch, not every path to it.

4

Cost, and adopting incrementally

Each visible prefetch={true} link can wake a server, so a grid of cards is one render per card as they enter the viewport. Prefetch on hover for dense lists; the default link carries no such cost. To adopt without flipping the whole app, set prefetch = 'partial' per route, then enable the global flag and remove the exports (the remove-partial-prefetch codemod does this).

Choosing the prefetch behavior
SituationChoice
Route shares a static or cached shell.Default link. It warms the shared shell.
Route depends on the URL and that content is worth prefetching.<Link prefetch={true}> on that link.
Whole route depends on the URL, no useful shell.instant = false. Dynamic by design.
Rarely visited page behind auth.prefetch = 'force-disabled'.
Check yourself

Your app upgraded to Cache Components and users report product pages feel slower to open, though nothing errors. Detail pages are keyed by [slug] and links are plain <Link>. What is the most likely cause?

What you learned

  • A default link now warms the shared App Shell, not the whole route.
  • prefetch={true} means "resolve this link's URL data," not "prefetch everything."
  • Relying on the old full prefetch can silently regress; audit router.prefetch() by hand.
  • The link states intent; the prefetch export sets the cost ceiling.
  • force-disabled still allows metadata and parent-driven prefetches.

Last lesson: making prefetch={true} pay off, and bringing per-user session data into the shell without leaking it into a shared cache.