In Next.js, what does adding the `'use cache'` directive at the top of a file, an async function, or a component actually do?
answer
- opt-in, not automatic
- a directive, like 'use client'
- file, function, or component
- result stored, keyed by inputs
- not limited to fetch
basics
~20 sThe 'use cache' directive marks a file, async function, or component as cacheable. Next.js runs it once, stores the returned value on the server under a key derived from its inputs, and reuses that value on later requests until it is revalidated.
solid answer
~50 s`'use cache'` is Next's explicit opt-in for server-side caching. You put the string literal at the very top of a file, an async function, or a component; Next then treats that unit's output as cacheable, stores it in a server cache keyed by the inputs it was called with, and serves the stored value to later requests instead of re-running the work. It is not tied to `fetch` — any async work qualifies, including a database query or a third-party SDK call. Scope follows placement: on a file, every export is cached; on a component, its rendered output is cached. In Next 15 and 16 the directive is still opt-in behind a flag in `next.config`, which is the whole point of the feature — the framework is moving from caching by default to caching where you say so.
code
typescript · 12 lines// app/lib/products.ts
'use cache'
export async function getProducts(category: string) {
const res = await fetch(`https://api.example.com/products/${category}`)
return res.json()
}
export async function getCategories() {
const res = await fetch('https://api.example.com/categories')
return res.json()
}go deeper
Know that 'use cache' is a directive you write as a bare string at the top of a file, async function, or component, and that it tells Next.js to store and reuse that unit's result on the server.
Be able to explain that placement decides scope, that the value must be serializable because it is stored and replayed, and that any async work qualifies rather than just fetch.
Show you know the entry is shared across requests and users by default, so the design question is which work is genuinely user-independent before you reach for the directive at all.
Own the framing that this is a shift from opt-out to opt-in caching: argue what the team gains in readability and what it costs in upgrade risk when previously-static routes go dynamic.
## The directive family Next.js uses a small set of string-literal directives to mark units of code with a special meaning for the compiler. `'use client'` marks a module boundary in the graph, `'use server'` marks functions callable from the client, and `'use cache'` marks work whose *result* may be stored and replayed. All three are written as a bare string on the first line of a file or as the first statement of a function body, above any imports or code in that scope. ```ts // app/lib/products.ts 'use cache' export async function getProducts(category: string) { const res = await fetch(`https://api.example.com/products/${category}`) return res.json() } ``` ## What "cacheable" means here When a `'use cache'` function runs, Next computes a key from what went into the call, runs the body, and writes the returned value into a server-side cache. The next request that produces the same key does not run the body at all — it gets the stored value back. Because the value is stored and replayed, the function must be `async` and its return value must be serializable; you cannot cache a live database handle or a function. The important word is *server-side*. The entry lives on the server (or on your hosting platform's cache tier), it is shared across requests, and by default it is shared across users. That sharing is exactly what makes it fast and exactly what makes it dangerous for anything request-specific. ## Placement decides scope - **Top of a file** — every export of that module is cached. Convenient for a `lib/` module that only holds data-loading helpers; dangerous in a file that also exports something user-specific. - **Top of an async function** — only that function is cached. This is the common case and the one you should reach for first, because the blast radius is one function. - **Top of a component** — the component's rendered output is cached, so Next can skip re-rendering that subtree. ```ts export async function getPricing(plan: string) { 'use cache' return db.plan.findUnique({ where: { slug: plan } }) } ``` ## Not a fetch feature A persistent misunderstanding is that Next caching only ever applied to `fetch`. Historically the framework patched `fetch` and derived caching from it, which left ORM calls, file reads and SDK calls uncovered — teams wrapped those by hand. `'use cache'` is deliberately mechanism-agnostic: whatever the async function does, the *result* is what gets cached, so a Prisma query and an S3 read are cacheable on the same terms as an HTTP call. ## Opt-in, not automatic In Next 15 and 16 `'use cache'` is enabled by an opt-in flag in `next.config`; it is not on out of the box, and the flag name has moved between canaries, so check the docs for the version you are on rather than memorising it. The direction it represents is the durable part: caching used to be something the framework did for you and you opted out of, and it is becoming something you request explicitly at the call site. The upside is that a reader can see, in the source, which work is cached. The downside is that an upgrade can turn previously-static pages dynamic until you add the directives back. ## What you tune next A bare `'use cache'` uses a default lifetime. Two helpers from `next/cache` refine it: `cacheLife()` sets how long the entry stays usable and when it refreshes, and `cacheTag()` attaches a label so `revalidateTag()` can invalidate it later. (In earlier Next 15 canaries these were exported with `unstable_` prefixes.) Neither changes what the directive fundamentally does — they only control the entry's lifetime and how you throw it away. ## What it does not do It does not make a client component cacheable — it is a server-side mechanism and belongs in server code. It does not add caching to the browser. And it does not make request-specific data safe to cache: reading a cookie or header inside a cached function is a correctness problem, not a configuration one.
- Does `'use cache'` only cover data loaded with `fetch`?No. It caches whatever the async unit returns, so a Prisma or Drizzle query, an S3 read, or a third-party SDK call is cached on the same terms as an HTTP request. That is the main practical gain over the older fetch-centric model, where non-fetch data access had to be wrapped by hand.
- What happens differently if you put `'use cache'` at the top of a file instead of on one function?Every export in that module becomes cached, not just the one you had in mind. That is fine for a module of pure data loaders, but it silently caches anything user-specific you later add to the same file. Function-level placement keeps the blast radius to one function.
- Can you put `'use cache'` in a client component file?No — it is a server-side caching mechanism and belongs in server code. A client component can call a cached server function indirectly, through a Server Component that renders it or a server function it invokes, but the directive itself has no meaning in a `'use client'` module.
saying these in an interview costs you the question
- Thinks 'use cache' caches in the user's browser
- Believes it only applies to fetch calls
- Assumes it is enabled by default in every Next version
- Says it can be used inside a client component
- Thinks the directive goes in next.config rather than in code