Module A-3·32 min read

Request Memoization mechanics, Data Cache tag registry and purge API, use cache directive internals, cacheLife profiles, cacheTag/updateTag, use cache: private and remote, custom cacheHandlers, and cache stampede prevention.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

A-3 — The Caching Architecture: Deep Internals

Who this is for: Architects who've used the four caching layers from P-7 and need to understand how they actually work internally — the tag registry mechanics, cache stampede and its prevention, how use cache derives its keys, custom cache handlers for distributed deployments, and the failure modes that only appear at scale.


Request Memoization Internals

Request Memoization is implemented inside React's fetch patch. When Next.js starts a request, it patches the global fetch with a version that checks an in-memory Map before making a network call. The map key is a hash of the URL and the init options object.

The Map lives on the React async context — it's scoped to a single React render tree. It's created when rendering begins and cleared when the response is sent. Two components calling fetch('https://api.example.com/user/123') in the same render share the same map entry.

What Request Memoization does not deduplicate:

  • Database calls through Prisma or any ORM (they don't go through fetch)
  • fetch calls with different init options (different headers, different methods)
  • fetch calls across different requests (the Map is per-request, not persistent)

For database queries, React.cache() wraps a function in its own per-request memoisation map. The mechanics are the same — in-memory Map, per-request scope, keyed by the function reference and serialised arguments.


Data Cache Tag Registry

The Data Cache stores fetch results and use cache results keyed by a cache key. Every entry can have zero or more tags associated with it. Tags are how you group cache entries for batch invalidation.

The tag registry is a separate data structure: a Map from tag string to Set of cache keys that carry that tag. When you call revalidateTag('products'), Next.js:

  1. Looks up 'products' in the tag registry → gets the Set of cache keys
  2. Marks each of those cache keys as stale in the Data Cache
  3. The next request for any of those cache keys re-fetches from origin and stores the fresh result

The registry and cache are stored on disk in production (.next/cache/fetch-cache by default) so they survive serverless function restarts. In development, they're in memory only.

The tag registry with multiple caches:

In a multi-instance deployment (multiple Node.js servers), each server has its own Data Cache on its own filesystem. Calling revalidateTag('products') on server A invalidates the cache on server A — but server B still has the stale entry. If the next request for that data lands on server B, it serves stale.

This is the distributed cache invalidation problem. The solution is a custom cache handler backed by shared storage (Redis, Upstash).


Custom Cache Handler for Distributed Deployments

ts
ts

With a Redis-backed cache handler, all server instances share the same cache. revalidateTag('products') on any server invalidates the cache for all servers. ISR works correctly in a multi-instance deployment.

When you need a custom cache handler:

  • More than one server instance (horizontal scaling, multiple regions)
  • Kubernetes deployments with rolling updates (pods have independent filesystems)
  • Any deployment where filesystem state can't be shared

Vercel handles this automatically — their infrastructure uses a shared cache backend. Self-hosted single-instance deployments with a persistent filesystem (a single Docker container) work fine with the default file-based cache.


Cache Stampede — The Production Failure Mode

Cache stampede (also called thundering herd) is what happens when a popular cached entry expires and many concurrent requests all try to revalidate at the same time.

Timeline:

text

Prevention strategies:

Staggered TTLs — add random jitter to revalidation times so not all entries expire simultaneously:

ts

cacheLife with separate stale and revalidate windows:

ts

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.