The `use cache` Directive: File, Function, and Component Scope

The use cache directive works at file, function, and component scope. Learn what each placement caches, how cache keys are built, and the constraints.

8 min read

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:

typescripttypescript
// 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.tsxApp.tsx
// 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.

typescripttypescript
// 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

ScopePlacementWhat gets cachedMust be async
FunctionInside the function bodyThat function's return valueYes
ComponentInside the component bodyThe component's outputYes
FileFirst line of the fileEvery exported functionYes

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(), and searchParams are 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

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.
RunePowered by Rune AI

Frequently Asked Questions

Does use cache work in Client Components?

No. The directive runs on the server and marks server-side functions and components. It is not a client-side hook.

Must a cached function be async?

Yes. Functions and components that use the use cache directive must be async, because the directive caches their resolved return value.

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.