Open-Source Wikis

/

Next.js

/

Systems

/

Caching

vercel/next.js

Caching

Three caching layers in the framework, in increasing order of granularity:

  1. Incremental cache — full-page HTML and JSON for ISR / SSG.
  2. Fetch cache (patch-fetch.ts) — per-request memoization of fetch() calls in server code.
  3. Use cache — the new 'use cache' directive that caches arbitrary server function results.

Cache components, the umbrella feature, ties these together. When __NEXT_CACHE_COMPONENTS=true, most app-dir pages enable PPR implicitly and the framework's caching defaults shift toward stale-while-revalidate by default.

Incremental cache

packages/next/src/server/lib/incremental-cache/ is the pre-existing on-disk cache for full-page renders, JSON props, and image-optimizer output.

  • In-memory layer — LRU cache for hot pages.
  • On-disk layer.next/cache/ directory with per-route subdirectories.
  • Pluggable handlers — users can swap to Redis or any custom store via cacheHandler in next.config.js.

Built-in handlers under packages/next/src/server/lib/incremental-cache/:

Handler When
file-system-cache.ts Default. Writes to .next/cache/
fetch-cache.ts Default for fetched data

The cache implementation tracks revalidation through packages/next/src/server/lib/cache-handlers/ — these are the per-data-kind cache entries (e.g., a separate handler for prerender HTML vs JSON props).

Fetch cache (patch-fetch)

packages/next/src/server/lib/patch-fetch.ts (47 KB) is one of the largest single files in the runtime. It monkey-patches the global fetch() to:

  • Memoize identical requests within a single render (deduplication).
  • Cache responses across renders, scoped to the work-unit async storage.
  • Honor revalidation via next.revalidate / next.tags request options.
  • Trigger revalidation when revalidatePath or revalidateTag is called.
graph TD
    UserFetch[await fetch(url, opts)] --> Patched[patched fetch]
    Patched --> Memo{In-memory<br/>memoization?}
    Memo -- hit --> Return[return memoized]
    Memo -- miss --> CheckCache{In incremental<br/>cache?}
    CheckCache -- hit + fresh --> Return
    CheckCache -- hit + stale --> Background[background revalidate<br/>return stale]
    CheckCache -- miss --> RealFetch[do real fetch]
    RealFetch --> WriteCache[write to incremental cache]
    WriteCache --> Memo2[memoize in render]
    Memo2 --> Return

A separate dedupe-fetch.ts (4 KB) handles request deduplication for the App Router specifically — multiple components rendering against the same fetch() call get the same promise.

Use cache

packages/next/src/server/use-cache/use-cache-wrapper.ts (2,861 lines) implements the 'use cache' directive. When a server function declares 'use cache', the framework:

  1. Compiles it via the SWC transform that recognizes the directive.
  2. Wraps the function with cache machinery: a stable cache key derived from arguments, lookup against the cache handler, write-on-miss behavior.
  3. Tracks cache scope through work-unit-async-storage.external.ts.

The cache key is derived from the function's source location plus the arguments (after they're encoded). The cache handler is the same pluggable layer used by the incremental cache.

Other files under packages/next/src/server/use-cache/:

  • cache-handler.ts — the dispatch to the configured cache handler
  • cache-life.ts — the cacheLife API for setting per-call TTLs
  • cache-tag.ts — the cacheTag API for invalidation by tag
  • crypto-key.ts — derives encryption keys for cached values
  • default-cache-life.ts — default cache lifetimes by profile name

Cache components

The umbrella feature flag __NEXT_CACHE_COMPONENTS=true enables:

  • PPR by default for app-dir pages.
  • A unified caching surface via 'use cache'.
  • Different default revalidation behavior (stale-while-revalidate becomes the norm).

The legacy ppr-full/ and ppr/ test suites are mostly describe.skip while this migration completes — to test PPR codepaths today, run normal app-dir e2e tests with the cache components flag set.

Revalidation

Three APIs trigger cache invalidation:

API Effect
revalidatePath(path) Invalidates all cache entries tagged for this path
revalidateTag(tag) Invalidates all cache entries with this tag
next.revalidate: <s> Per-fetch TTL

Implementation: packages/next/src/server/revalidation-utils.ts. The router-server checks the revalidation flags after each response and may trigger background re-renders.

ISR (Incremental Static Regeneration)

ISR is an emergent behavior of the incremental cache: a page with getStaticProps + revalidate: 60 gets served from disk for 60 seconds, then re-fetched in the background. After regeneration, the new HTML replaces the old.

The implementation is the cooperation between:

  • incremental-cache/ (storage)
  • static-paths-worker.ts (regeneration in a worker)
  • revalidation-utils.ts (TTL accounting)

Implicit tags

packages/next/src/server/lib/implicit-tags.ts (3 KB) generates implicit cache tags for incoming requests so framework operations (revalidation by path, revalidation by tag) can be coordinated even when the user doesn't supply explicit tags.

Stale-time and cache-control

packages/next/src/server/app-render/stale-time.ts and packages/next/src/server/lib/cache-control.ts produce the Cache-Control headers attached to responses. The headers reflect the per-route rendering mode (static, ISR, dynamic) and any revalidate config.

Disk LRU

packages/next/src/server/lib/disk-lru-cache.external.ts provides a generic disk-backed LRU used by the incremental cache and the image optimizer.

Integration points

  • Patches the global fetch once, on first render in a render scope.
  • Uses async storage to know "we are inside a render" — bare fetch() calls outside a render context behave normally.
  • Coordinates with the build pipeline through prerender-manifest.json.
  • Honors user-supplied cacheHandler for both ISR and 'use cache'.

Entry points for modification

  • To change fetch-cache behavior: packages/next/src/server/lib/patch-fetch.ts.
  • To change the use-cache wrapper: packages/next/src/server/use-cache/use-cache-wrapper.ts.
  • To add a new revalidation primitive: packages/next/src/server/revalidation-utils.ts plus the public re-export under packages/next/src/api/cache.ts.
  • To add a cache handler kind: packages/next/src/server/lib/cache-handlers/.

Key source files

File Purpose
packages/next/src/server/lib/incremental-cache/ ISR / SSG / fetch on-disk cache
packages/next/src/server/lib/patch-fetch.ts Patched global fetch
packages/next/src/server/lib/dedupe-fetch.ts App Router fetch deduplication
packages/next/src/server/use-cache/use-cache-wrapper.ts 'use cache' runtime
packages/next/src/server/use-cache/cache-handler.ts Cache handler dispatch
packages/next/src/server/use-cache/cache-life.ts cacheLife API
packages/next/src/server/use-cache/cache-tag.ts cacheTag API
packages/next/src/server/revalidation-utils.ts revalidatePath, revalidateTag plumbing
packages/next/src/server/lib/implicit-tags.ts Implicit tags from request shape
packages/next/src/server/app-render/stale-time.ts Cache-Control header generation
packages/next/src/server/lib/cache-handlers/ Per-data-kind handler implementations

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Caching – Next.js wiki | Factory