"use cache" goes at the top of an async function body, of a component, or of a whole file — in which case every export it covers must be async. Compare two pages doing the same work. The first is the default: a render that has to happen per request, so it needs connection() and a boundary.
async function Clock() {
await connection();
return <p>rendered at {new Date().toISOString()} — render #{bump("live")}</p>;
}Its page renders <Suspense fallback={<p>Loading...</p>}><Clock /></Suspense>. The cached version swaps connection() for a directive and needs no boundary. bump() is a counter in a plain module returning how many times it has been called, so the page reports how often the body actually ran.
async function Clock() {
"use cache";
cacheLife("max");
return <p>rendered at {new Date().toISOString()} — render #{bump("cached")}</p>;
}Three requests to each, against next start after a build that finished at 05:57:55:
/live rendered at 2026-09-22T05:58:31.642Z — render #1
rendered at 2026-09-22T05:58:31.827Z — render #2
rendered at 2026-09-22T05:58:31.977Z — render #3
/cached rendered at 2026-09-22T05:57:55.278Z — render #1
rendered at 2026-09-22T05:57:55.278Z — render #1
rendered at 2026-09-22T05:57:55.278Z — render #1The cached body ran once, at build time, and every request since replayed that result. new Date() is allowed inside use cache — the value freezes with the entry — but outside one it is a build error.
What makes an entry unique
A cache key hashes four things: the build ID, the function's location and signature, the serialized arguments, and, in development only, a hot-reload hash. Arguments include anything captured from an enclosing scope:
async function Component({ userId }) {
const getData = async (filter) => {
"use cache";
return (await fetch(`https://api.example.com/u/${userId}?f=${filter}`)).json();
};
return getData("active");
}userId comes from the closure and filter from the call, and each combination gets its own entry. Because the build ID is in the key, no entry survives a deployment.
Arguments must satisfy React 7,897 's Server Component serialization — primitives, plain objects, arrays, Date, Map, Set, typed arrays — and return values the looser Client Component rules, which also allow JSX. Class instances, functions and URL objects are rejected. The exception is pass-through: children, other slots and Server Actions may be re-emitted untouched, which is what lets a cached layout wrap dynamic children.