---
title: "Response Cache"
description: "The Response Cache subsystem is a server-level architectural component responsible for coordinating, batching, keying, and retaining rendered application payloads and HTML results across requests. ..."
last_updated: "2026-09-23T10:52:03.199778+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/caching-and-export/response-cache"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/next/src/server/use-cache/use-cache-wrapper.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/use-cache/use-cache-wrapper.ts)
- [packages/next/src/server/response-cache/index.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts)
- [packages/next/src/server/route-modules/route-module.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/route-modules/route-module.ts)
- [packages/next/src/server/app-render/app-render.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/app-render.tsx)
- [packages/next/src/client/components/segment-cache/cache.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/cache.ts)
- [packages/next/src/server/lib/patch-fetch.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/patch-fetch.ts)
- [packages/next/src/client/dev/debug-channel.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/dev/debug-channel.ts)
- [packages/next/src/client/components/router-reducer/fetch-server-response.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/fetch-server-response.ts)
- [packages/next/src/server/web/spec-extension/unstable-cache.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/web/spec-extension/unstable-cache.ts)
- [packages/next/src/server/app-render/instant-validation/instant-validation.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/instant-validation/instant-validation.tsx)
- [packages/next/src/server/route-modules/pages/pages-handler.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/route-modules/pages/pages-handler.ts)
- [packages/next/src/server/response-cache/web.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/web.ts)
- [packages/next/src/server/lib/incremental-cache/file-system-cache.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/lib/incremental-cache/file-system-cache.ts)
- [packages/next/src/client/components/router-reducer/ppr-navigations.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/router-reducer/ppr-navigations.ts)
- [packages/next/src/client/components/segment-cache/bfcache.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/segment-cache/bfcache.ts)
- [packages/next/src/server/render-result.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts)
- [packages/next/src/server/response-cache/utils.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/utils.ts)
- [packages/next/src/server/app-render/action-handler.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/action-handler.ts)
- [packages/next/src/server/request-meta.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/server/request-meta.ts)
</details>

## Overview

### Overview Intro

The Response Cache subsystem is a server-level architectural component responsible for coordinating, batching, keying, and retaining rendered application payloads and HTML results across requests. In Next.js rendering pipelines (spanning both Pages and App Routers), multiple concurrent requests for the same route can arrive simultaneously. Without centralized control, this concurrency triggers redundant renders, race conditions, and excessive memory utilization. The `ResponseCache` class and its accompanying request-meta utilities solve this by intercepting lookups, wrapping generation callbacks inside specialized batchers (`Batcher.create`), and integrating with underlying incremental persistence layers (`IncrementalCache` or filesystem caches).

Sources: [packages/next/src/server/response-cache/index.ts:107-190](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L107-L190)

A core design decision in the response cache architecture is the decoupling of cache key generation from raw pathname strings through compound keys. By combining pathnames with invocation identifiers (`invocationID`) or fallback TTL sentinels (`TTL_SENTINEL`), the subsystem prevents conflicting overlapping renders in minimal server modes or on-demand revalidation tasks. Furthermore, the subsystem manages execution flow between volatile memory (`LRUCache`) and persistent backends, ensuring that background revalidations (`waitUntil`) do not block incoming client responses while maintaining strict cache integrity.

Sources: [packages/next/src/server/response-cache/index.ts:53-104](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L53-L104), [packages/next/src/server/response-cache/index.ts:138-190](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L138-L190)

The subsystem interacts tightly with `RouteModule` dispatchers, `RenderResult` abstractions, and asynchronous storage contexts (`workAsyncStorage`, `workUnitAsyncStorage`). By standardizing how cache entries are parsed, converted (`toResponseCacheEntry`, `fromResponseCacheEntry`), and protected against stampedes, the response cache provides a reliable bridge between dynamic server-side rendering logic and static distribution targets.

Sources: [packages/next/src/server/response-cache/utils.ts:14-40](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/utils.ts#L14-L40), [packages/next/src/server/route-modules/route-module.ts:1103-1173](https://github.com/blade47/next.js/blob/main/packages/next/src/server/route-modules/route-module.ts#L1103-L1173)

---

## Public API and Interface Surface

### Surface Overview

The response cache subsystem exposes class-based interfaces for managing cached route responses and minimal-mode memory entries. The primary implementation is `ResponseCache`, adhering to the `ResponseCacheBase` contract, alongside a lighter `WebResponseCache` implementation for edge/web runtimes lacking persistent incremental cache bindings.

Sources: [packages/next/src/server/response-cache/index.ts:107-218](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L107-L218)

- `ResponseCache`: Main server-side cache manager. Implements `get()` to coordinate lookup, request batching, and cache population.
- `WebResponseCache`: Lightweight map-based response cache used in web runtimes where incremental cache stores are unavailable.
- `RenderResult`: Encapsulates response payloads (strings, buffers, or readable streams) along with route metadata (headers, status codes, revalidation controls).

Sources: [packages/next/src/server/response-cache/web.ts:8-32](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/web.ts#L8-L32), [packages/next/src/server/render-result.ts:111-201](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts#L111-L201)

| Component / Class | Primary Method | Input Parameters | Return Type | Description |
| :--- | :--- | :--- | :--- | :--- |
| `ResponseCache` | `get` | `key`, `responseGenerator`, `context` | `Promise<ResponseCacheEntry \| null>` | Batches and resolves cached entries or invokes generation. |
| `WebResponseCache` | `get` | `key`, `responseGenerator`, `context` | `Promise<ResponseCacheEntry \| null>` | Manages in-memory pending promises for web runtimes. |
| `RenderResult` | `toUnchunkedString` | `stream?: boolean` | `string \| Promise<string>` | Converts response streams or buffers into a unified string. |

Sources: [packages/next/src/server/response-cache/index.ts:200-218](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L200-L218), [packages/next/src/server/render-result.ts:199-201](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts#L199-L201)

---

## Compound Key Generation and Invalidation Logic

Cache lookup keys in `ResponseCache` are not simple pathnames. To support minimal mode and background revalidation tasks without data contamination, the subsystem constructs compound keys joining the route pathname with an invocation identifier or fallback sentinel.

Sources: [packages/next/src/server/response-cache/index.ts:85-91](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L85-L91)

```mermaid
flowchart TD
    A["Incoming Request"] --> B{"Has invocationID?"}
    B -- Yes --> C["Compound Key: pathname + '\0' + invocationID"]
    B -- No --> D["Compound Key: pathname + '\0' + '__ttl_sentinel__'"]
    C --> E["LRU Cache Lookup"]
    D --> E
    E --> F{"Cache Hit & Valid?"}
    F -- Yes --> G["Return Cached Response Entry"]
    F -- No --> H["Batch & Execute Response Generator"]
```

Sources: [packages/next/src/server/response-cache/index.ts:229-260](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L229-L260)

The compound key structure uses a null byte (`\0`) separator (`KEY_SEPARATOR`) because null bytes cannot appear in valid URL paths or UUIDs. When `minimal_mode` is enabled, entries are stored in a bounded `LRUCache` instance.

Sources: [packages/next/src/server/response-cache/index.ts:59-91](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L59-L91), [packages/next/src/server/response-cache/index.ts:138-190](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L138-L190)

> [!NOTE]
> When `invocationID` is undefined, the subsystem falls back to `TTL_SENTINEL` (`__ttl_sentinel__`) and validates entries against a configurable Time-To-Live (`DEFAULT_TTL_MS`, defaulting to 10 seconds). Memory pressure is managed via LRU eviction rather than active timers.

Sources: [packages/next/src/server/response-cache/index.ts:44-81](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L44-L81)

---

## Request Batching and Concurrency Control

To prevent cache stampedes and duplicate render passes when multiple concurrent requests target an uncached route, `ResponseCache` utilizes two internal `Batcher` instances: `getBatcher` and `revalidateBatcher`.

Sources: [packages/next/src/server/response-cache/index.ts:108-131](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L108-L131)

```typescript
private readonly getBatcher = Batcher.create<
  { key: string; isOnDemandRevalidate: boolean },
  IncrementalResponseCacheEntry | null,
  string
>({
  cacheKeyFn: ({ key, isOnDemandRevalidate }) =>
    `${key}-${isOnDemandRevalidate ? '1' : '0'}`,
  schedulerFn: scheduleOnNextTick,
})
```

Sources: [packages/next/src/server/response-cache/index.ts:108-122](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L108-L122)

When `ResponseCache.get()` is invoked:
1. If `key` is null, it bypasses caching entirely and immediately executes the `responseGenerator`.
2. In minimal mode, the LRU cache is checked. If a valid entry exists (or a TTL-valid item is found), it is converted via `toResponseCacheEntry` and returned.
3. Otherwise, the request is passed to `getBatcher.batch()`. The batcher ensures that subsequent lookups with identical keys during the current tick reuse the pending promise.
4. Background revalidations are registered with `waitUntil(promise)` to ensure serverless containers or Node runtimes do not prematurely terminate execution.

Sources: [packages/next/src/server/response-cache/index.ts:219-307](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L219-L307)

---

## Call-Chain Execution Walkthrough

The following walkthrough traces the verified execution path from route handling through response cache lookup, conversion, static instantiation, and result wrapping (`handleResponse` → `get` → `toResponseCacheEntry` → `fromStatic` → `RenderResult`):

Sources: [packages/next/src/server/route-modules/route-module.ts:1111-1171](https://github.com/blade47/next.js/blob/main/packages/next/src/server/route-modules/route-module.ts#L1111-L1171), [packages/next/src/server/response-cache/index.ts:200-307](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L200-L307), [packages/next/src/server/response-cache/utils.ts:42-79](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/utils.ts#L42-L79), [packages/next/src/server/render-result.ts:149-158](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts#L149-L158), [packages/next/src/server/render-result.ts:110-170](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts#L110-L170)

1. **Route Module Handler**: `RouteModule.handleResponse()` receives rendering options and calls `responseCache.get(cacheKey, responseGenerator, context)`.
2. **Response Cache Lookup**: `ResponseCache.get()` verifies keys, checks memory caches, or delegates to `handleGet()` via the batcher to load incremental cache payloads.
3. **Entry Transformation**: `toResponseCacheEntry()` transforms stored incremental entries into `ResponseCacheEntry` structures.
4. **Static Instantiation**: `RenderResult.fromStatic()` wraps static string or buffer payloads along with the HTML content type.
5. **Render Result Construction**: The final `RenderResult` instance is returned to the handler for pipeline dispatch.

Sources: [packages/next/src/server/route-modules/route-module.ts:1138-1155](https://github.com/blade47/next.js/blob/main/packages/next/src/server/route-modules/route-module.ts#L1138-L1155), [packages/next/src/server/response-cache/index.ts:306-307](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L306-L307), [packages/next/src/server/response-cache/utils.ts:42-79](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/utils.ts#L42-L79), [packages/next/src/server/render-result.ts:149-170](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts#L149-L170)

```mermaid
sequenceDiagram
    participant RM as RouteModule
    participant RC as ResponseCache
    participant UT as ResponseCacheUtils
    participant RR as RenderResult

    RM->>RC: handleResponse() -> responseCache.get()
    RC-->>UT: toResponseCacheEntry(incrementalEntry)
    UT->>RR: RenderResult.fromStatic(value, contentType)
    RR-->>RM: RenderResult instance
```

Sources: [packages/next/src/server/route-modules/route-module.ts:1138-1171](https://github.com/blade47/next.js/blob/main/packages/next/src/server/route-modules/route-module.ts#L1138-L1171), [packages/next/src/server/response-cache/utils.ts:42-79](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/utils.ts#L42-L79), [packages/next/src/server/render-result.ts:149-158](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts#L149-L158)

---

## Data Structures and Type Coercion

The response cache converts internal cache records between storage formats and runtime render results using conversion utility functions.

Sources: [packages/next/src/server/response-cache/utils.ts:1-40](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/utils.ts#L1-L40)

- `ResponseCacheEntry`: Runtime representation containing `RenderResult` instances (`html`), headers, status codes, and `CacheControl` metadata.
- `IncrementalResponseCacheEntry`: Serialized representation where HTML and RSC payloads are stored as unchunked strings or binary buffers (`Buffer`).

Sources: [packages/next/src/server/response-cache/index.ts:1-10](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L1-L10)

| Utility Function | Source Type | Target Type | Conversion Purpose |
| :--- | :--- | :--- | :--- |
| `fromResponseCacheEntry` | `ResponseCacheEntry` | `IncrementalResponseCacheEntry` | Prepares runtime HTML/RSC streams for disk/cache serialization by unchunking strings. |
| `toResponseCacheEntry` | `IncrementalResponseCacheEntry` | `ResponseCacheEntry` | Wraps raw serialized strings/buffers into `RenderResult` instances for execution. |
| `routeKindToIncrementalCacheKind` | `RouteKind` | `IncrementalCacheKind` | Maps route module kinds to their corresponding incremental cache storage folder/type. |

Sources: [packages/next/src/server/response-cache/utils.ts:14-99](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/utils.ts#L14-L99)

> [!CAUTION]
> Dynamic responses cannot be unchunked synchronously. Attempting to call `toUnchunkedString()` on an active stream without specifying `stream: true` will throw an `InvariantError`.

Sources: [packages/next/src/server/render-result.ts:202-219](https://github.com/blade47/next.js/blob/main/packages/next/src/server/render-result.ts#L202-L219)

---

## Error Handling and Eviction Edge Cases

The response cache subsystem implements specific guardrails for memory exhaustion, eviction monitoring, and missing cache entries:

Sources: [packages/next/src/server/response-cache/index.ts:142-190](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L142-L190)

- **Eviction Tracking**: When the internal `LRUCache` evicts an entry in minimal mode, the eviction listener extracts the `invocationID` from the compound key and registers it in `evictedInvocationIDs` (bounded to 100 entries). If a subsequent request matches an evicted invocation ID, `warnOnce` logs a warning advising the developer to increase `NEXT_PRIVATE_RESPONSE_CACHE_MAX_SIZE`.
- **Invariant Enforcement**: If a cache key is provided during a response handling pass, but no cache entry is returned and revalidation-only-generated checks do not bail out, the server throws an invariant error: `'invariant: cache entry required but not generated'`.
- **Background Error Handling**: In `WebResponseCache`, errors thrown during background revalidation are caught and logged if the response promise has already resolved, preventing unhandled rejections from crashing the worker.

Sources: [packages/next/src/server/response-cache/index.ts:145-190](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/index.ts#L145-L190), [packages/next/src/server/route-modules/route-module.ts:1157-1171](https://github.com/blade47/next.js/blob/main/packages/next/src/server/route-modules/route-module.ts#L1157-L1171), [packages/next/src/server/response-cache/web.ts:114-126](https://github.com/blade47/next.js/blob/main/packages/next/src/server/response-cache/web.ts#L114-L126)

## Related

- [Incremental Cache](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/caching-and-export/incremental-cache)
- [Server Request Lifecycle](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/server-request-lifecycle)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/llms.txt) for all pages in this wiki.
