Mastering Next.js Caching: How to Perfectly Balance ISR, SSR, and Data Revalidation Without Serving Stale Content

Most stale-content bugs in production Next.js apps aren't caused by a missing revalidate call. They're caused by a mismatch between what a developer thinks a cache boundary does and what it actually does. Next.js runs four distinct caching layers stacked on top of each other — Request Memoization, the Data Cache, the Full Route Cache, and the Router Cache — and Incremental Static Regeneration (ISR) is not a fifth mechanism sitting beside them. It's a policy applied to two of those layers. Understanding that distinction is the difference between a cache strategy that holds up under real traffic and one that quietly serves a pricing page from three deploys ago.

The Four Layers, and Why They Don't Fail Together

The mental model most teams carry over from the Pages Router — "static or server-rendered, pick one" — breaks down in the App Router because caching now happens independently at each of four points in the request lifecycle.

Request Memoization deduplicates identical fetch calls within a single render pass. If three components on the same page call the same API endpoint with identical parameters, Next.js executes that request once and shares the result across all three, but only for the lifetime of that single render — it never persists across requests. This layer is invisible to settings entirely; it resets on every incoming request.