Skip to content

Commit 0553b34

Browse files
doc: instant navs runtime story (#93204)
- changes getting started -> caching - new guide for instant navs - new guide for runtime-prefetching (most pending stuff is here) - x-refs between docs - App Shell mentions in other docs (ISR w/ CC) --------- Co-authored-by: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com> Co-authored-by: Aurora Scharff <aurora.sofie@gmail.com>
1 parent 23b1977 commit 0553b34

21 files changed

Lines changed: 874 additions & 210 deletions

docs/01-app/01-getting-started/08-caching.mdx

Lines changed: 240 additions & 112 deletions
Large diffs are not rendered by default.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
---
2+
title: Adopting Partial Prefetching
3+
nav_title: Adopting Partial Prefetching
4+
description: Learn how to enable Partial Prefetching and what changes for `<Link>`.
5+
version: draft
6+
related:
7+
title: Next Steps
8+
description: Learn more about prefetching and instant navigations.
9+
links:
10+
- app/guides/instant-navigation
11+
- app/guides/runtime-prefetching
12+
- app/api-reference/components/link
13+
- app/api-reference/config/next-config-js/partialPrefetching
14+
---
15+
16+
[Partial Prefetching](/docs/app/glossary#partial-prefetching) changes what `<Link>` downloads for a Cache Components route. By default, a `<Link>` loads a per-route [App Shell](/docs/app/glossary#app-shell), and the page's cached content is downloaded only when the link sets `prefetch={true}`. This is the biggest change from the pre-Cache Components behavior, where fully static pages were always prefetched by default.
17+
18+
`<Link prefetch={true}>` also stops prefetching dynamic content. It now only prefetches the cached parts of the page, so the link no longer pulls cookies, headers, or other request-time data ahead of the navigation.
19+
20+
> **Good to know**: Partial Prefetching only works when [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) is enabled.
21+
22+
## What changes for `<Link>`
23+
24+
| `<Link>` prop | Before (Cache Components default) | After Partial Prefetching |
25+
| ----------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------- |
26+
| `<Link href="/x">` | Prefetched the cached page render. | Loads the App Shell for `/x`. |
27+
| `<Link href="/x" prefetch>` | Prefetched the cached page render **and** any dynamic content. | Loads the App Shell **and** the cached page content. |
28+
| `<Link href="/x" prefetch={false}>` | Disabled prefetching for this link. | Unchanged. Still disabled. |
29+
30+
The App Shell is shared across every link to a given route, regardless of dynamic params, so rendering many `<Link>`s to the same destination doesn't multiply the work.
31+
32+
## Adopting in a new project
33+
34+
Enable [`partialPrefetching`](/docs/app/api-reference/config/next-config-js/partialPrefetching) in `next.config.ts` alongside Cache Components:
35+
36+
```ts filename="next.config.ts" highlight={5}
37+
import type { NextConfig } from 'next'
38+
39+
const nextConfig: NextConfig = {
40+
cacheComponents: true,
41+
partialPrefetching: true,
42+
}
43+
44+
export default nextConfig
45+
```
46+
47+
Add `prefetch` to any `<Link>` whose destination's cached content is worth shipping ahead of the navigation. Leave it off for the rest:
48+
49+
```tsx filename="app/page.tsx"
50+
import Link from 'next/link'
51+
52+
export default function Page() {
53+
return (
54+
<nav>
55+
<Link href="/products">Products</Link>
56+
<Link href="/checkout" prefetch>
57+
Checkout
58+
</Link>
59+
</nav>
60+
)
61+
}
62+
```
63+
64+
## Adopting incrementally in an existing project
65+
66+
If you can't enable `partialPrefetching` for the entire app at once, opt routes in one at a time with the [`prefetch`](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) route segment config:
67+
68+
```tsx filename="app/products/[slug]/page.tsx"
69+
export const prefetch = 'partial'
70+
71+
export default function Page() {
72+
return <div>...</div>
73+
}
74+
```
75+
76+
A `<Link>` pointing at a route with `prefetch = 'partial'` loads the App Shell only, even when `partialPrefetching` is not set in `next.config.ts`.
77+
78+
Once every route in scope has `prefetch = 'partial'`, enable the config and remove the per-route exports:
79+
80+
```ts filename="next.config.ts" highlight={5}
81+
import type { NextConfig } from 'next'
82+
83+
const nextConfig: NextConfig = {
84+
cacheComponents: true,
85+
partialPrefetching: true,
86+
}
87+
88+
export default nextConfig
89+
```
90+
91+
## Next steps
92+
93+
- [Runtime prefetching](/docs/app/guides/runtime-prefetching) for per-link runtime prefetches and App Shells in depth.
94+
- [`partialPrefetching` API reference](/docs/app/api-reference/config/next-config-js/partialPrefetching) for the global config flag.
95+
- [`prefetch` API reference](/docs/app/api-reference/file-conventions/route-segment-config/prefetch) for the per-segment prefetch config.
96+
- [`<Link>` API reference](/docs/app/api-reference/components/link#prefetch) for the per-link `prefetch` prop.
97+
- [Instant navigation](/docs/app/guides/instant-navigation) to validate that the routes you've marked actually navigate instantly.

docs/01-app/02-guides/incremental-static-regeneration-cache-components.mdx

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
---
22
title: Incremental Static Regeneration with Cache Components
3-
description: Learn how to prerender a subset of dynamic routes, serve fallback shells for the rest, and upgrade them after the first visit.
3+
description: Learn how to prerender a subset of dynamic routes, serve App Shells for the rest, and upgrade them after the first visit.
44
nav_title: ISR with Cache Components
5-
version: experimental
65
related:
76
links:
87
- app/api-reference/config/next-config-js/cacheComponents
@@ -11,12 +10,14 @@ related:
1110
- app/getting-started/caching
1211
---
1312

14-
[Incremental Static Regeneration (ISR)](/docs/app/glossary#incremental-static-regeneration-isr) with [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) lets you:
13+
[Incremental Static Regeneration (ISR)](/docs/app/glossary#incremental-static-regeneration-isr) with [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) gives every route an instant first visit, even for URLs that weren't included in the build.
1514

16-
- Prerender a subset of your dynamic routes at build time with [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)
17-
- For routes not included in that subset, prerender a **fallback shell**: the static UI Next.js can produce by treating params as runtime data
18-
- Serve something instantly for every route: either the prerendered page or the fallback shell
19-
- Progressively improve what visitors see for a given route as param values become known from real traffic
15+
During build, Partial Prerendering splits each render into two parts:
16+
17+
- The **App Shell**: the generic, reusable part of the page that doesn't depend on URL data
18+
- The rest of the statically renderable content: the param-specific prerenders for the URLs you list in [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)
19+
20+
For a visit to a URL whose params were included in `generateStaticParams`, Next.js serves the fully prerendered page from the cache. For a visit to a URL whose params weren't, Next.js serves the App Shell instantly, then upgrades it in the background with the now-known params. Subsequent visits to that URL get the upgraded result from the cache, skipping the App Shell entirely.
2021

2122
If you have used [ISR](/docs/app/guides/incremental-static-regeneration) or [`fallback: true`](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths#fallback-true) in the Pages Router, this is the Cache Components equivalent.
2223

@@ -41,7 +42,7 @@ We'll build a product catalog with category layouts and product detail pages usi
4142

4243
### Prepare your routes
4344

44-
Use [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) to define which param values to prerender. When rendering these routes, the param values are known at build time. The prerender process builds a static shell until it hits runtime APIs or uncached data. See [how rendering works](/docs/app/getting-started/caching#how-rendering-works) for more details.
45+
Use [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) to define which param values to prerender. When rendering these routes, the param values are known at build time. The prerender process builds a static shell until it hits runtime APIs or uncached data. See [Prerendering](/docs/app/getting-started/caching#prerendering) for more details.
4546

4647
The category layout prerenders two categories:
4748

@@ -82,7 +83,7 @@ export default function CategoryLayout(props: LayoutProps<'/[category]'>) {
8283
}
8384
```
8485

85-
Notice that `CategoryLayout` does not `await props.params` itself. Instead, it passes the `params` promise to `CategoryHeader` inside `<Suspense>`. The `await` happens inside the boundary, so for unknown categories Next.js can still generate a static shell with the fallback UI.
86+
Notice that `CategoryLayout` does not `await props.params` itself. Instead, it passes the `params` promise to `CategoryHeader` inside `<Suspense>`. The `await` happens inside the boundary, so for unknown categories Next.js can still generate the App Shell.
8687

8788
The product page prerenders one product per category. `generateStaticParams` receives the parent `category` param:
8889

@@ -167,9 +168,9 @@ If your components access runtime APIs like `cookies` or `headers`, wrap them in
167168

168169
### At build time
169170

170-
When you run `next build`, Next.js prerenders the layout for each known category (`tops`, `shorts`), plus one render where `await params` suspends, producing the `[category]` shell.
171+
When you run `next build`, Next.js prerenders the layout for each known category (`tops`, `shorts`), plus one render where `await params` suspends, producing the App Shell for `[category]`.
171172

172-
It also prerenders the page for each known product under each category (`tee` under `tops`, `joggers` under `shorts`), plus one render where `await params` suspends, producing the `[product]` shell.
173+
It also prerenders the page for each known product under each category (`tee` under `tops`, `joggers` under `shorts`), plus one render where `await params` suspends, producing the App Shell for `[product]`.
173174

174175
These are combined into:
175176

@@ -181,21 +182,21 @@ These are combined into:
181182

182183
A visitor navigates to `/tops/tee`. Both params were prerendered. They get a fully static page.
183184

184-
The first visit to `/tops/overshirt`. The product is unknown, but the category `tops` was prerendered. Next.js serves the `/tops/[product]` shell with the category header already rendered. The product streams in.
185+
The first visit to `/tops/overshirt`. The product `overshirt` is unknown, but the category `tops` was prerendered. Next.js serves the App Shell for `/tops/[product]` with the category header already rendered. The product streams in.
185186

186-
The first visit to `/shoes/basketball-shoes`. The category `shoes` was not prerendered. Next.js serves the generic `/[category]/[product]` shell. Both the category and the product stream in.
187+
The first visit to `/shoes/basketball-shoes`. Neither param was prerendered. Next.js serves the generic App Shell for `/[category]/[product]`. Both the category and the product stream in.
187188

188-
After the first visit, Next.js renders these routes in the background with the now-known params. The next visitor to the same URLs gets a more specific result.
189+
After the first visit, Next.js renders these routes in the background with the now-known params. The next visitor to the same URLs gets the upgraded result.
189190

190191
### What the upgrade produces
191192

192193
After the first visit, Next.js renders the page in the background with the known params and tries to push the static boundary as far down the component tree as possible:
193194

194195
- If every data access is cached and all params are resolved, the upgrade produces a **fully static page**.
195-
- If some data is uncached or runtime APIs (`cookies`, `headers`) are accessed behind `<Suspense>` fallbacks, the upgrade produces a **more specific shell** with the params resolved but the dynamic parts still streaming.
196-
- Params are resolved in route order. A param without `generateStaticParams` blocks all subsequent params from upgrading.
196+
- If all params are resolved but the render still hits uncached data or runtime APIs (`cookies`, `headers`) wrapped in `<Suspense>` boundaries, the upgrade produces a **cached page with those fallbacks**. The uncached or runtime parts stream in at request time.
197+
- Params are resolved in route order. A param value not returned by `generateStaticParams` stays unresolved and prevents any deeper params from upgrading.
197198

198-
> **Good to know**: Prefetching also triggers upgrades. When a [`<Link>`](/docs/app/api-reference/components/link) enters the viewport or [`router.prefetch`](/docs/app/api-reference/functions/use-router) is called, Next.js can upgrade the shell in the background, so the next visitor gets the more specific version even before anyone actually navigates to the page.
199+
> **Good to know**: Prefetching also triggers upgrades. When a [`<Link>`](/docs/app/api-reference/components/link) enters the viewport or [`router.prefetch`](/docs/app/api-reference/functions/use-router) is called, Next.js can upgrade the App Shell in the background, so the next visitor gets the more specific version even before anyone actually navigates to the page.
199200
200201
## Coming from the Pages Router
201202

@@ -210,6 +211,6 @@ If you are migrating from the Pages Router:
210211

211212
- [Caching with Cache Components](/docs/app/getting-started/caching) for the full caching model
212213
- [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params) for controlling which param combinations are prerendered
213-
- [`loading.tsx`](/docs/app/api-reference/file-conventions/loading) for providing skeleton UI in fallback shells
214+
- [`loading.tsx`](/docs/app/api-reference/file-conventions/loading) for providing skeleton UI in App Shells
214215
- [Streaming](/docs/app/guides/streaming) to learn how to progressively render UI as data becomes available
215216
- [Self-hosting](/docs/app/guides/self-hosting#caching-and-isr) to keep an existing ISR [`cacheHandler`](/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath) alongside [`cacheHandlers`](/docs/app/api-reference/config/next-config-js/cacheHandlers) for `'use cache'`

0 commit comments

Comments
 (0)