100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
JavaScript

Caching in Next.js

A tour of the four caching mechanisms in the Next.js App Router — Request Memoization, the Data Cache, the Full Route Cache, and the Router Cache — and how they interact.

Data FetchingAdvanced11 min readJul 10, 2026
Analogies

The Four Caching Layers in Next.js

Next.js layers four distinct caching mechanisms that each solve a different problem: Request Memoization dedupes identical fetch calls within a single render pass on the server; the Data Cache persists fetch results across requests and deployments on the server; the Full Route Cache stores the rendered HTML and RSC payload for statically rendered routes at build time; and the Router Cache stores route segment payloads in the browser's memory for instant back/forward navigation. Understanding which layer is responsible for stale data is the single most common source of confusion when debugging a Next.js app that 'won't update.'

🏏

Cricket analogy: Like a cricket broadcast having separate systems for the live scorer's notepad, the official archive scorecard, the stadium's printed program, and a fan's own memory of who's batting — each serving a different purpose.

When debugging 'stale data' in Next.js, always ask which of the four layers is holding the old value: was the fetch memoized within one render, cached in the Data Cache, baked into the Full Route Cache, or just sitting in a visitor's client-side Router Cache?

The Data Cache: Persisting fetch Results

The Data Cache stores the results of fetch requests on the server so that, by default, a fetch call is cached indefinitely across requests and even across deployments unless you specify otherwise; you opt out per-call with { cache: 'no-store' } or set a time-based expiry with { next: { revalidate: 3600 } }. Tagging a fetch with { next: { tags: ['products'] } } lets you later invalidate exactly that cached entry on demand with revalidateTag('products') without waiting for its time-based expiry.

🏏

Cricket analogy: Like a stadium's ground staff keeping yesterday's pitch report on file indefinitely unless someone specifically orders a fresh pitch inspection before the next match.

ts
// Tagged, time-based Data Cache entry
async function getProducts() {
  const res = await fetch('https://api.store.com/products', {
    next: { revalidate: 3600, tags: ['products'] },
  });
  return res.json();
}

// Opting a specific fetch out of the Data Cache entirely
async function getLiveInventory(sku: string) {
  const res = await fetch(`https://api.store.com/inventory/${sku}`, {
    cache: 'no-store',
  });
  return res.json();
}

Full Route Cache and Static Rendering

Routes that don't rely on dynamic APIs like cookies() or searchParams are statically rendered at build time and their HTML plus RSC payload are stored in the Full Route Cache, meaning every visitor to /blog/hello-world gets served the exact same pre-rendered response until it's revalidated or the app is redeployed. Setting export const dynamic = 'force-dynamic' on a page, or using a dynamic function anywhere in its render tree, opts that specific route out of the Full Route Cache and forces server rendering on every request instead.

🏏

Cricket analogy: Like a printed match program distributed to the whole stadium ahead of time, identical for every seat, versus a personalized replay clip generated specifically for one fan's phone.

Using a dynamic function such as cookies(), headers(), or searchParams anywhere in a page's component tree — even deep inside a nested Server Component — opts the entire route out of the Full Route Cache, not just that one component.

The Router Cache: Client-Side Navigation

The Router Cache lives entirely in the browser's memory and stores the RSC payload for route segments you've already visited, so clicking back to a previously visited page renders instantly from that in-memory cache instead of re-fetching from the server; static segments are cached by default for a long period while dynamic segments have a much shorter cache window. Because this cache lives client-side, a server-side revalidateTag() call won't automatically clear a stale entry sitting in a user's Router Cache until they trigger a hard navigation or the cache's own timer expires.

🏏

Cricket analogy: Like a fan who already watched an over live keeping that memory fresh in their head, so replaying it in their mind is instant, unlike waiting for the broadcaster to re-air it.

  • Request Memoization dedupes identical fetch calls within a single server render pass.
  • The Data Cache persists fetch results on the server across requests and deployments, by default indefinitely.
  • Tagging a fetch with next.tags lets you invalidate exactly that entry later with revalidateTag.
  • The Full Route Cache stores a statically rendered route's HTML and RSC payload at build time.
  • Any dynamic function used anywhere in a route's component tree opts the whole route out of the Full Route Cache.
  • The Router Cache lives in the browser and makes back/forward navigation between visited routes instant.
  • A server-side revalidateTag call does not automatically clear a stale Router Cache entry already in a user's browser.

Practice what you learned

Was this page helpful?

Topics covered

#JavaScript#NextJsStudyNotes#WebDevelopment#CachingInNextJs#Caching#Next#Four#Layers#StudyNotes#SkillVeris