ESC

Type to search the knowledge base.

Caching in Next.js Overview

Next.js caching layers: request memoization, data cache, full route cache, and router cache — what invalidates each.

advanced3 min read
  • nextjs
  • caching-in

Next.js App Router performance comes from multiple caches. Confusing them causes “why is my data stale?” interviews and incidents.

Docs: Caching in Next.js.

Four layers (mental model)

Layer What Lifetime (approx)
Request memoization Dedupes fetch during one server render Single request
Data Cache Persistent fetch results across requests Until revalidate/tag
Full Route Cache Static RSC payload / HTML for a route Build or revalidate
Router Cache Client-side session cache of visited segments Navigation session (version-dependent defaults)

Exact defaults evolve — always verify against current docs for your Next version.

fetch controls

fetch(url, { cache: 'no-store' }); // dynamic
fetch(url, { next: { revalidate: 3600 } }); // ISR-style
fetch(url, { next: { tags: ['product'] } }); // tag invalidation

Opting into dynamic

Using cookies(), headers(), uncached data, or certain searchParams patterns can mark a route dynamic so the Full Route Cache is not used for that request path.

Invalidation

  • Time-based revalidate
  • revalidateTag('product') / revalidatePath('/shop') after mutations
  • See revalidate path and tag

Interview out-loud

“Next caches at request, data, full route, and client router layers. fetch options choose static revalidation or no-store. Dynamic APIs bypass static route caching. Mutations call revalidateTag or revalidatePath to refresh durable caches.”

Further reading

Edge cases worth rehearsing

Interviewers and production incidents cluster around the same edges: first render versus update, empty and loading states, Strict Mode double setup, concurrent interruptions, and what happens when identity (key, route params, user id) changes mid-edit. Walk one concrete user journey end-to-end — open, edit, navigate away, come back — and say which state survives.

Prefer fixing data flow and ownership before reaching for memoization or micro-optimizations. Prefer event handlers over effects when a user action is the trigger. Prefer deriving values during render over mirroring props into state. Prefer stable list keys from business ids. Measure with the profiler when performance is the claim.

When you cite an API, mention one failure mode: abort on unmount, serializable props across server/client boundaries, focus restoration for dialogs, or cache invalidation after a mutation. Specific beats generic every time.

Edge cases worth rehearsing

Interviewers and production incidents cluster around the same edges: first render versus update, empty and loading states, Strict Mode double setup, concurrent interruptions, and what happens when identity (key, route params, user id) changes mid-edit. Walk one concrete user journey end-to-end — open, edit, navigate away, come back — and say which state survives.

Prefer fixing data flow and ownership before reaching for memoization or micro-optimizations. Prefer event handlers over effects when a user action is the trigger. Prefer deriving values during render over mirroring props into state. Prefer stable list keys from business ids. Measure with the profiler when performance is the claim.

When you cite an API, mention one failure mode: abort on unmount, serializable props across server/client boundaries, focus restoration for dialogs, or cache invalidation after a mutation. Specific beats generic every time.

Related guides