The use cache directive marks a function, component, or file as cacheable in the App Router. It is part of Cache Components, so it only works after you set cacheComponents: true in your config. Functions and components that use it must be async.
The directive reads the same in all three scopes, but its reach changes. In function scope it caches one function's return value:
// app/lib/posts.ts
import { cacheLife } from 'next/cache'
export async function getPosts() {
'use cache'
cacheLife('hours')
const res = await fetch('https://api.example.com/posts')
return res.json()
}The first call runs the body and stores the result. Later calls with the same arguments reuse it until the cacheLife lifetime ends. This runs on the server and is useful when several components need the same data.
Component scope
Placed inside a component body, the directive caches the component's output. The cache entry is keyed by the serialized props, so each distinct prop combination gets its own entry.
// app/components/Bookings.tsx
import { cacheLife } from 'next/cache'
export async function Bookings({ type }: { type: string }) {
'use cache'
cacheLife('hours')
const res = await fetch(`https://api.example.com/bookings?type=${type}`)
const bookings = await res.json()
return <ul>{bookings.map((b) => <li key={b.id}>{b.title}</li>)}</ul>
}Rendering this component with type set to haircut produces one cached entry. Rendering it with type set to nails produces another. Both are shared across users, and the list appears in the prerendered shell instead of streaming in.
File scope
Placed as the first line of a file, the directive applies to every exported function in that file. Every covered export must be async.
// app/lib/posts.ts
'use cache'
export async function getPosts() {
const res = await fetch('https://api.example.com/posts')
return res.json()
}
export async function getAuthors() {
const res = await fetch('https://api.example.com/authors')
return res.json()
}Both functions are now cached without repeating the directive on each one. Framework exports are covered too, so generateMetadata and generateStaticParams in such a file must also be async.
The scopes compared
| Scope | Placement | What gets cached | Must be async |
|---|---|---|---|
| Function | Inside the function body | That function's return value | Yes |
| Component | Inside the component body | The component's output | Yes |
| File | First line of the file | Every exported function | Yes |
Choose the narrowest scope that covers the work. A one-off helper belongs in function scope, while a page or layout that should prerender as a whole belongs in file scope. Component scope sits between them, useful when the same component renders in several routes and its output can be shared.
How cache keys work
An entry's key is built from several inputs, not just the function name.
- The build ID, so a new deploy starts with empty caches.
- A hash of the function's location and signature.
- The serializable arguments or props.
- Variables captured from an outer scope, which become part of the key automatically.
Because captured values join the key, two calls that read the same argument but different captured values store separate entries. When a cached function reads root params, only the ones it actually reads join the key. In development, an HMR refresh hash is also part of the key, so edits invalidate the cache.
See the use cache private variant for the case where you must keep results per user.
Constraints
- A cached scope cannot read request data.
cookies(),headers(), andsearchParamsare unavailable inside it, so read them outside and pass values as arguments. - Arguments and return values must be serializable. Dates, Maps, and plain objects serialize fine, while class instances and functions do not serialize as arguments.
- React cache is isolated inside a use cache boundary, so data stored through it outside is not visible inside.
- Draft Mode re-executes cached scopes on every request and does not save results.
For how lifetimes tune this behavior, see cacheLife explained. For durable shared storage across instances, see the use cache remote variant.
Common mistakes
- Adding the directive to a synchronous function, which fails because cached functions must be async.
- Reading cookies inside the cached scope instead of passing the value in as an argument.
- Expecting the directive to work without enabling Cache Components first.
Rune AI
Key Insights
- use cache marks a function, component, or file as cacheable.
- Function scope caches one return value.
- Component scope caches the component output, keyed by props.
- File scope caches every exported function.
- Cached scopes must be async and cannot read request data.
Frequently Asked Questions
Does use cache work in Client Components?
Must a cached function be async?
Conclusion
The use cache directive caches one return value per scope. Function scope caches a single function, component scope caches a component's output, and file scope caches every exported function. Keep cached scopes free of request data and pass runtime values in as arguments.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.