next
Version:
The React Framework
178 lines (130 loc) • 10.1 kB
Markdown
---
title: prefetch
nav_title: prefetch
description: Defer runtime work until a per-link prefetch or navigation with the prefetch function.
related:
links:
- app/guides/optimizing-prefetching
- app/guides/keeping-pages-static
- app/api-reference/functions/navigation
- app/api-reference/functions/connection
- app/api-reference/config/next-config-js/partialPrefetching
---
Calling `await prefetch()` keeps runtime work below it out of the route's [App Shell](/docs/app/glossary#app-shell). The work can run during a per-link prefetch or navigation, while the fallback of the nearest [`<Suspense>`](https://react.dev/reference/react/Suspense) boundary renders in the shell.
Use `prefetch()` for content that the App Shell would otherwise render but that is expensive to generate. Static prerenders still include the content in their output.
## Usage
The function requires [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents) and throws an error if not enabled. Without [Partial Prefetching](/docs/app/api-reference/config/next-config-js/partialPrefetching) a route has no App Shell, so the function has no effect. Enable Partial Prefetching globally, or one route at a time, by [adopting Partial Prefetching](/docs/app/guides/adopting-partial-prefetching).
```ts filename="next.config.ts" highlight={4,5}
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
cacheComponents: true,
partialPrefetching: true,
}
export default nextConfig
```
With Partial Prefetching enabled, Next.js loads server-rendered output in stages, before and during a client navigation. These are the route's [navigation stages](/docs/app/glossary#navigation-stages):
1. A default `<Link>` loads the App Shell, which holds the part of the route that does not depend on the URL.
2. An optional [`<Link prefetch={true}>`](/docs/app/api-reference/components/link#prefetch) can also load content that depends on the link's URL.
3. When the user follows the link, the navigation renders the rest of the route.
During runtime rendering, awaiting `prefetch()` keeps content out of the App Shell, so it renders during a per-link prefetch or navigation. Static prerenders can still include the content.
To keep content out of per-link prefetches as well, so it renders only on the navigation, use [`navigation()`](/docs/app/api-reference/functions/navigation).
> **Good to know**: `prefetch()` defers one subtree. To require a static App Shell across the route, use [`ensureStatic = 'shell'`](/docs/app/api-reference/file-conventions/route-segment-config/ensureStatic#shell). See [Keeping pages static](/docs/app/guides/keeping-pages-static) for a worked example.
Everything above `prefetch()` renders in the App Shell, and everything below renders on a per-link prefetch or on the navigation. Deferral is scoped to the component that awaits it and the tree below: sibling branches render in the shell as usual. Place it above the work to defer, and wrap the component in [`<Suspense>`](https://react.dev/reference/react/Suspense):
```tsx filename="app/dashboard/page.tsx" highlight={25} switcher
import { Suspense } from 'react'
import { cookies } from 'next/headers'
import { cacheLife, prefetch } from 'next/cache'
export default function Page() {
return (
<>
<Suspense fallback={<p>Loading greeting...</p>}>
<Greeting /> {/* in the App Shell */}
</Suspense>
<Suspense fallback={<p>Loading recommendations...</p>}>
{/* the fallback is in the App Shell, the recommendations are not */}
<Recommendations />
</Suspense>
</>
)
}
async function Greeting() {
const session = (await cookies()).get('session')?.value
return <p>{session ? 'Welcome back' : 'Welcome'}</p>
}
async function Recommendations() {
await prefetch() // runtime work below renders on a per-link prefetch or navigation
const items = await getRecommendations()
return <List items={items} />
}
async function getRecommendations() {
'use cache: private'
cacheLife('hours')
const session = (await cookies()).get('session')?.value
return db.recommendations.rank({ session })
}
```
```jsx filename="app/dashboard/page.js" highlight={25} switcher
import { Suspense } from 'react'
import { cookies } from 'next/headers'
import { cacheLife, prefetch } from 'next/cache'
export default function Page() {
return (
<>
<Suspense fallback={<p>Loading greeting...</p>}>
<Greeting /> {/* in the App Shell */}
</Suspense>
<Suspense fallback={<p>Loading recommendations...</p>}>
{/* the fallback is in the App Shell, the recommendations are not */}
<Recommendations />
</Suspense>
</>
)
}
async function Greeting() {
const session = (await cookies()).get('session')?.value
return <p>{session ? 'Welcome back' : 'Welcome'}</p>
}
async function Recommendations() {
await prefetch() // runtime work below renders on a per-link prefetch or navigation
const items = await getRecommendations()
return <List items={items} />
}
async function getRecommendations() {
'use cache: private'
cacheLife('hours')
const session = (await cookies()).get('session')?.value
return db.recommendations.rank({ session })
}
```
The greeting reads the session and stays in the App Shell. The recommendations read it too, inside `getRecommendations`, so that read is deferred along with the ranking. Remove `prefetch()` and they become part of the App Shell that every link into the route loads.
Put the directive on a function called below it, as `getRecommendations` does here. Awaiting `prefetch()` inside a cached scope, such as [`use cache`](/docs/app/api-reference/directives/use-cache) or [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), is not allowed.
## How `prefetch()` differs from `connection()`
The [`connection()`](/docs/app/api-reference/functions/connection) function waits for a real request. It excludes the code that follows from prerendering and prefetching, making that work request-dependent.
Awaiting `prefetch()` excludes the code that follows from the App Shell. It can resolve during a per-link prefetch without making that work request-dependent. A function called after `await prefetch()` can therefore use [`"use cache"`](/docs/app/api-reference/directives/use-cache) and keep its cache lifetime without generating its result for every link into the route.
Use `connection()` when the work must run for a real request. Use `prefetch()` when the work is reusable but should only run for a selected per-link prefetch or a navigation.
## When to use it
Use `prefetch()` when the content below it is expensive to produce and should not be generated in the App Shell that every `<Link>` into the route loads.
Producing the App Shell does not run that code, so its upstream requests are not issued until a per-link prefetch or the navigation.
Leaving content uncached also keeps it out of the shell, but gives up its cache lifetime and cannot make it available during a per-link prefetch. With `prefetch()`, the content can be cached with [`use cache`](/docs/app/api-reference/directives/use-cache) or [`use cache: private`](/docs/app/api-reference/directives/use-cache-private), given a lifetime, and deferred to a per-link prefetch or navigation.
Uncached reads, values with a short [`stale`](/docs/app/api-reference/functions/cacheLife#stale) time, and anything behind `params` or `searchParams` are already left out of the shell on their own.
### Keeping the App Shell static
When every read of [`cookies()`](/docs/app/api-reference/functions/cookies) and [`headers()`](/docs/app/api-reference/functions/headers) sits below `prefetch()`, the prerender a shell prefetch would trigger cannot produce more than the static output the build already generated, so the shell is served from that output instead. Shaping a route this way is an optional optimization: a static response can be cached in a CDN, so a default `<Link>` into the route costs no server CPU at all. A route that resolves `params` or `searchParams` gets that prerender instead, and so does the example above: its greeting reads the session in the shell, so the shell renders once per visitor and only the recommendations are deferred.
## Good to know
- The function has no effect on the initial load of a page.
- Unlike [`connection()`](/docs/app/api-reference/functions/connection), it does not mark the subtree as request-dependent. Content below `await prefetch()` stays fully cacheable and can be wrapped in [`use cache`](/docs/app/api-reference/directives/use-cache).
- A call outside a `<Suspense>` boundary surfaces an [Instant Insight](/docs/messages/instant-navigation-stage) in development. A fully prerendered route is unaffected, but the insight identifies that the call would defer content without a fallback if the route later requires runtime rendering.
- Calling it inside `use cache`, `use cache: private`, [`unstable_cache()`](/docs/app/api-reference/functions/unstable_cache), [`after()`](/docs/app/api-reference/functions/after), [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params), or a Client Component throws.
- In a `page` or `layout` that sets the [`prefetch` route segment config](/docs/app/api-reference/file-conventions/route-segment-config/prefetch), import the function under another name, for example `import { prefetch as prefetchStage } from 'next/cache'`, since both are named `prefetch`.
## Reference
### Type
```ts
function prefetch(): Promise<void>
```
### Parameters
- The function does not accept any parameters.
### Returns
A `Promise<void>`. It is not meant to be consumed.
## Version History
| Version | Changes |
| --------- | ---------------------------------------------------------------------------------------------- |
| `v16.4.0` | `prefetch` introduced, replacing the `unstable_prefetch` name used in earlier canary releases. |