Caching and freshness
Caching is a promise about acceptable staleness. Browser caching, CDN caching, and cached application work are different promises.
Start with acceptable staleness
Do not cache something just because it is expensive. First decide how stale the result is allowed to become. Documentation may tolerate long reuse; inventory may tolerate seconds; permissions may need request-time truth.
Once the freshness requirement is clear, choose the smallest cache boundary that satisfies it.
Do not confuse the layers
Static rendering is not browser caching
Static rendering answers when route output can be produced and reused. HTTP caching answers whether a browser or intermediary may reuse a response without fetching or revalidating it.
That is why a statically rendered page can still return browser-facing Cache-Control that requires revalidation while the hosting layer serves the route from its own cache.
Cache reusable work deliberately
With Cache Components enabled, 'use cache' marks work whose result can be reused. cacheLife describes its lifetime and cacheTag gives related data a domain name that mutations can invalidate.
The useful cache boundary is often smaller than a route. Stable sections can be reused while request-specific sections remain dynamic.
import { cacheLife, cacheTag } from 'next/cache'
export async function getProjects() {
'use cache'
cacheLife('hours')
cacheTag('projects')
return db.query.projects.findMany()
}Invalidate by meaning when you can
- revalidateTag(tag, 'max') fits stale-while-revalidate behaviour.
- updateTag(tag) is useful after a Server Action when the writer should immediately see fresh data.
- revalidatePath(path) refreshes by route when a precise domain tag is not available.
- Prefer tags such as projects or project:123 over names tied to a component.
Shared caches and personalised data are a dangerous mix
Do not put permission-sensitive or user-specific output into a shared cache unless the cache key and framework semantics truly isolate every value that changes the result.
Authentication state, ownership checks, tokens, and secrets should make you conservative. A fast response is not worth serving one user's data to another.
Do not mix caching models from different Next.js eras
Older tutorials often describe caching through a different set of defaults and route-level concepts. Current Cache Components documentation uses 'use cache', cacheLife, and cacheTag as the central model when the feature is enabled.
When maintaining an existing project, check its Next.js version and next.config.ts before copying a caching example from a newer guide.
Can you explain “Caching and freshness” without reaching for the API reference?
Describe the main trade-off, one failure mode, and the decision you would make in a real project.