---
title: "Segment Cache"
description: "The segment cache is a client-side subsystem in the Next.js App Router responsible for storing, coordinating, and incrementally retrieving React Server Component (RSC) route segments and shell data..."
last_updated: "2026-10-12T06:38:56.86852+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/segment-cache"
---

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

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

- [packages/next/src/client/components/segment-cache/cache.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts)
- [packages/next/src/client/components/segment-cache/bfcache.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts)
- [packages/next/src/client/components/render-tree.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/render-tree.ts)
- [packages/next/src/server/app-render/collect-segment-data.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx)
- [packages/next/src/client/components/segment-cache/decode-server-response.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts)
- [packages/next/src/client/components/segment-cache/scheduler.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts)
- [packages/next/src/build/templates/app-page-runtime.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/templates/app-page-runtime.ts)
- [packages/next/src/client/components/router-reducer/fetch-server-response.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/fetch-server-response.ts)
- [packages/next/src/client/components/router-reducer/create-initial-router-state.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/create-initial-router-state.ts)
- [packages/next/src/client/components/bfcache-state-manager.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/bfcache-state-manager.ts)
</details>

## Overview

The segment cache is a client-side subsystem in the Next.js [App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/app-router) responsible for storing, coordinating, and incrementally retrieving React Server Component (RSC) route segments and shell data. By caching individual route segments independently from full page responses, it enables fine-grained prefetching, partial prerendering (PPR) reuse, and low-latency client-side navigations without full document reloads or redundant network requests. The architecture relies on synchronous, mutable data structures and priority-scheduled prefetch tasks to manage cache entries, decode binary transport streams, and coordinate with the [Router Reducer](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/router-reducer) during state transitions.

Sources: [packages/next/src/client/components/segment-cache/cache.ts:141-160](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L141-L160), [packages/next/src/client/components/segment-cache/decode-server-response.ts:1-7](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L1-L7)

## Segment Cache Architecture and Node Hierarchy

### Core Data Structures and RouteTree Representations

The segment cache relies on synchronized data structures where route topology is modeled as a tree of segment nodes, and cached content is stored inside a mutable cache map. Avoidance of asynchronous operations (`async`/`await`) during cache reads enables synchronous tree traversal and immediate state snapshots for rendering. The cache entry lifecycle transitions through distinct status values defined by cache map protocol.

| Status Name | Value / Meaning |
| :--- | :--- |
| `Empty` | `EntryStatus.Empty` — The cache slot contains no data and has not been prefetched. |
| `Pending` | `EntryStatus.Pending` — A fetch or subtask is currently in flight for this entry. |
| `Fulfilled` | `EntryStatus.Fulfilled` — Data has been successfully received, decoded, and stored. |
| `Rejected` | `EntryStatus.Rejected` — The previous fetch or prefetch attempt failed; subject to retry backoff. |

Sources: [packages/next/src/client/components/segment-cache/cache.ts:141-160](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L141-L160), [packages/next/src/client/components/segment-cache/cache.ts:66-75](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L66-L75)

> [!NOTE]
> Async/await is intentionally avoided when reading from or traversing the prefetch cache. This constraint permits synchronous cache snapshots and prevents race conditions within the mutable cache map.

Sources: [packages/next/src/client/components/segment-cache/cache.ts:141-160](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L141-L160)

### Node Lifecycle within the Segment Cache Map

When segments are received from an RSC server response, the subsystem restarts traversal from the root of the tree being prefetched to verify that parent segments remain cached and reachable. If a segment is no longer reachable from the root, its task is canceled, mirroring the behavior of Rust futures or React Suspense. Stale times for entries enforce minimum thresholds to ensure prefetches remain valid; specifically, `getStaleTimeMs` enforces a minimum stale time of 30 seconds to prevent excessively short-lived values from blocking prefetches.

```typescript
/**
 * Ensures a minimum stale time of 30s to avoid issues where the server sends a too
 * short-lived stale time, which would prevent anything from being prefetched.
 */
export function getStaleTimeMs(staleTimeSeconds: number): number {
  return Math.max(staleTimeSeconds, 30) * 1000
}
```
Sources: [packages/next/src/client/components/segment-cache/cache.ts:111-117](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L111-L117), [packages/next/src/client/components/segment-cache/cache.ts:141-160](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L141-L160)

> [!WARNING]
> If a segment becomes unreachable from the root during an in-flight asynchronous operation, the subtask is treated as canceled and abandoned.

Sources: [packages/next/src/client/components/segment-cache/cache.ts:141-160](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L141-L160)

## Server Segment Data Collection

### Prerender Data Decoding and Staged Transport Formatting

Server-side segment data collection collect-segment-data.tsx decodes a full prerendered page buffer to drive per-segment prefetch generation. It warms up the module cache and reads embedding flags from the decoded `InitialRSCPayload`: `pageShellByteLength` (its `a` field) determines the shell boundary [packages/next/src/server/app-render/collect-segment-data.tsx:186-203](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L186-L203), and `runtimeDataAccessed` (its `u` field) captures whether runtime data like cookies or headers were read [packages/next/src/server/app-render/collect-segment-data.tsx:204-214](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L204-L214). When client parameter parsing is enabled via `isCacheComponentsEnabled`, wire identities use `createPrefetchTransportSegment` to omit parameter values (`k: null`) so responses remain byte-identical across parameters [packages/next/src/server/app-render/collect-segment-data.tsx:115-127](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L115-L127).

```tsx
export async function collectSegmentData(
  isCacheComponentsEnabled: boolean,
  fullPageDataBuffer: Buffer,
  staleTime: number,
  clientModules: ManifestNode,
  serverConsumerManifest: any,
  prefetchInlining: boolean,
  hints: PrefetchHints | null,
  isUpgradeableISRFallback: boolean
): Promise<Map<SegmentRequestKey, Buffer>> {
```
Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:157-166](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L157-L166), [packages/next/src/server/app-render/collect-segment-data.tsx:186-214](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L186-L214)

> [!NOTE]
> `createUnclosingPrefetchStream` wraps server streams in a readable stream that intentionally never closes, preventing Flight from erroring when dynamic data access leaves hanging promises unresolved [packages/next/src/server/app-render/collect-segment-data.tsx:1446-1476](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1446-L1476).

Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:1446-1476](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1446-L1476)

### Segment Sources, Spines, and Bundles

Segment data transmission tracks nested hierarchies using specific structural types defined during route traversal and rendering [packages/next/src/server/app-render/collect-segment-data.tsx:56-106](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L56-L106).

| Type Name | Field Signatures | Purpose |
| :--- | :--- | :--- |
| `SegmentSource` | `rsc: React.ReactNode`, `varyParams: VaryParamsIterable \| null` | Holds the RSC node and vary parameters for a single requested segment, bundled ancestor, or head [packages/next/src/server/app-render/collect-segment-data.tsx:56-59](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L56-L59). |
| `SegmentBundleNode` | `data: SegmentSource \| null`, `next: SegmentBundleNode \| null` | Linked list of ancestor data bundled into a descendant response, ordered nearest ancestor first [packages/next/src/server/app-render/collect-segment-data.tsx:72-75](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L72-L75). |
| `SegmentSpine` | `segment: TransportSegment`, `prefetchHints: number`, `parallelRouteKey: string \| null`, `parent: SegmentSpine \| null` | Maintains the identity path from the root down to the current segment during route traversal [packages/next/src/server/app-render/collect-segment-data.tsx:77-106](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L77-L106). |

Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:56-106](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L56-L106)

> [!WARNING]
> A `SegmentBundleNode` with a `null` `data` field marks a segment with static prefetching explicitly disabled (`prefetch: 'force-disabled'`), passing parent data through while carrying identity only [packages/next/src/server/app-render/collect-segment-data.tsx:67-70](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L67-L70).

Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:67-70](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L67-L70)

### Transport Data and Prefetch Handling

During client requests, server runtime handlers inspect `segmentPrefetchHeader` values to match segments [packages/next/src/build/templates/app-page-runtime.ts:2067-2093](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/templates/app-page-runtime.ts#L2067-L2093). When a matching segment exists within `cachedData.segmentData`, the server responds via `sendRenderResult` with static content and an RSC content type header, setting `NEXT_DID_POSTPONE_HEADER` to `'2'` to indicate partial prerendering enablement [packages/next/src/build/templates/app-page-runtime.ts:2075-2106](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/templates/app-page-runtime.ts#L2075-L2106). If no match is found, it responds with a 404 status and an empty render result [packages/next/src/build/templates/app-page-runtime.ts:2111-2120](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/templates/app-page-runtime.ts#L2111-L2120).

```typescript
  typeof segmentPrefetchHeader === 'string' &&
  cachedData?.kind === CachedRouteKind.APP_PAGE &&
  cachedData.segmentData
) {
  // This is a prefetch request issued by the client Segment Cache. These
  // should never reach the application layer (lambda). We should either
  // respond from the cache (HIT) or respond with 404 (MISS).

  // Set a header to indicate that PPR is enabled for this route. This
  // lets the client distinguish between a regular cache miss and a cache
  // miss due to PPR being disabled. In other contexts this header is used
  // to indicate that the response contains dynamic data, but here we're
  // only using it to indicate that the feature is enabled — the segment
  // response itself contains whether the data is dynamic.
  res.setHeader(NEXT_DID_POSTPONE_HEADER, '2')

  // Add the cache tags header to the response if it exists and we're in
  // minimal mode while rendering a static page.
  const tags = cachedData.headers?.[NEXT_CACHE_TAGS_HEADER]
  if (isMinimalMode && isSSG && tags && typeof tags === 'string') {
    res.setHeader(NEXT_CACHE_TAGS_HEADER, tags)
  }

  const matchedSegment = cachedData.segmentData.get(
    segmentPrefetchHeader
  )
  if (matchedSegment !== undefined) {
    // Cache hit
    return sendRenderResult({
      req,
      res,
      generateEtags: nextConfig.generateEtags,
      poweredByHeader: nextConfig.poweredByHeader,
      result: RenderResult.fromStatic(
        matchedSegment,
        RSC_CONTENT_TYPE_HEADER
      ),
      cacheControl: cacheEntry.cacheControl,
    })
  }

  // Cache miss. Either a cache entry for this route has not been generated
  // (which technically should not be possible when PPR is enabled, because
  // at a minimum there should always be a fallback entry) or there's no
  // match for the requested segment. Respond with a 404.
  res.statusCode = 404
  return sendRenderResult({
    req,
    res,
    generateEtags: nextConfig.generateEtags,
    poweredByHeader: nextConfig.poweredByHeader,
    result: RenderResult.EMPTY,
    cacheControl: cacheEntry.cacheControl,
  })
}
```
Sources: [packages/next/src/build/templates/app-page-runtime.ts:2067-2121](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/templates/app-page-runtime.ts#L2067-L2121)

## Prefetch Task Scheduling and Priority

### Prefetch Queue Management and Link Tracking

Client-side prefetch tasks are queued and prioritized by the scheduler to coordinate route navigations and background segment fetching [packages/next/src/client/components/segment-cache/scheduler.ts:62-80](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L62-L80). Each `PrefetchTask` tracks its target route key, the active render tree and head at the time of prefetch (`renderTreeAtTimeOfPrefetch`), and the distinct version numbers for both route and segment caches (`routeCacheVersion`, `segmentCacheVersion`) to detect invalidation [packages/next/src/client/components/segment-cache/scheduler.ts:62-80](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L62-L80). The scheduler schedules tasks using microtasks via `queueMicrotask` (with a timeout fallback) and monitors link visibility changes through `pingVisibleLinks` to adjust task priorities dynamically [packages/next/src/client/components/segment-cache/scheduler.ts:50-60](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L50-L60), [packages/next/src/client/components/segment-cache/cache.ts:93](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L93).

> [!NOTE]
> `isPrefetchTaskDirty` compares the target route against `renderTreeAtTimeOfPrefetch` by reference identity, relying on the router state holding a single `RootRouteTree` object per committed navigation [packages/next/src/client/components/segment-cache/scheduler.ts:62-70](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L62-L70).

Sources: [packages/next/src/client/components/segment-cache/scheduler.ts:62-70](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L62-L70), [packages/next/src/client/components/segment-cache/scheduler.ts:50-60](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L50-L60), [packages/next/src/client/components/segment-cache/cache.ts:93](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L93)

### Heap Priority Resifting and Fetch Strategies

Task priorities govern order within the scheduling heap, resifting tasks according to whether they originate from high-priority user interactions or background link visibility [packages/next/src/client/components/segment-cache/scheduler.ts:38](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L38). When executing prefetch walks, the client determines fetch strategies based on route configuration and whether static or runtime data is required [packages/next/src/client/components/segment-cache/scheduler.ts:2165-2173](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L2165-L2173).

| Fetch Strategy Name | Value / Type | Purpose |
| :--- | :--- | :--- |
| `StaticShell` | `FetchStrategy.StaticShell` | Provides the shell-stage variant extracted from a static response, omitting session-dependent content [packages/next/src/client/components/segment-cache/cache.ts:3843-3847](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3843-L3847). |
| `RuntimeShell` | `FetchStrategy.RuntimeShell` | Renders the runtime shell stage, capable of including content that depends on session data like cookies and headers [packages/next/src/client/components/segment-cache/cache.ts:3846-3847](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3846-L3847). |
| `PPR` | `FetchStrategy.PPR` | Provides static shells for each segment at concrete paths while excluding dynamic data [packages/next/src/client/components/segment-cache/cache.ts:3848-3849](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3848-L3849). |
| `PPRRuntime` | `FetchStrategy.PPRRuntime` | Includes content that utilizes searchParams, params, or cookies alongside PPR structures [packages/next/src/client/components/segment-cache/cache.ts:3850](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3850). |
| `Full` | `FetchStrategy.Full` | Retrieves all segment content, including dynamic data and runtime components [packages/next/src/client/components/segment-cache/cache.ts:3851](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3851). |

Sources: [packages/next/src/client/components/segment-cache/cache.ts:3841-3852](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3841-L3852), [packages/next/src/client/components/segment-cache/scheduler.ts:36-39](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L36-L39)

> [!WARNING]
> During static prefetch walks (`pingSegmentBundle`), rejected entries or segments lacking prerender shells bypass retry revaluations or trigger specific fallback rules depending on whether `canNewFetchStrategyProvideMoreContent` permits upgrading the strategy [packages/next/src/client/components/segment-cache/scheduler.ts:2219-2222](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L2219-L2222), [packages/next/src/client/components/segment-cache/scheduler.ts:2248-2262](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L2248-L2262).

Sources: [packages/next/src/client/components/segment-cache/scheduler.ts:2219-2222](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L2219-L2222), [packages/next/src/client/components/segment-cache/scheduler.ts:2248-2262](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/scheduler.ts#L2248-L2262)

## RSC Response Stream Decoding

### Response Buffering and Tree Construction

Client-side segment caching relies on decoding binary and streamed server responses into structured `RouteTree` topologies, navigation seeds, vary parameters, and cache entries [packages/next/src/client/components/segment-cache/decode-server-response.ts:1-6](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L1-L6). The decoding boundary processes transport nodes defined in `shared/lib/rsc-transport` and constructs navigable representations [packages/next/src/client/components/segment-cache/decode-server-response.ts:1-6](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L1-L6), [packages/next/src/client/components/segment-cache/decode-server-response.ts:18-21](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L18-L21).

Prefetch responses are read to completion and buffered into a single contiguous `Uint8Array` via `bufferPrefetchResponseBody` before being processed by the Flight client [packages/next/src/client/components/segment-cache/cache.ts:3732-3735](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3732-L3735). Buffering ensures all model data is available synchronously, allowing synchronous reads of thenable statuses such as vary parameters, partiality flags, and stale times without asynchronous interleaving between network chunks [packages/next/src/client/components/segment-cache/cache.ts:3718-3725](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3718-L3725). Conversely, dynamic or full prefetches use `createIncrementalPrefetchResponseStream` to incrementally update cache entry sizes in the LRU map without buffering [packages/next/src/client/components/segment-cache/cache.ts:3788-3792](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3788-L3792), [packages/next/src/client/components/segment-cache/cache.ts:3795-3808](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3795-L3808).

```typescript
export async function bufferPrefetchResponseBody(
  body: ReadableStream<Uint8Array>,
  byteLimit?: number
): Promise<Uint8Array> {
```
Sources: [packages/next/src/client/components/segment-cache/cache.ts:3732-3735](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3732-L3735), [packages/next/src/client/components/segment-cache/cache.ts:3718-3725](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3718-L3725), [packages/next/src/client/components/segment-cache/cache.ts:3788-3808](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3788-L3808)

> [!NOTE]
> `bufferPrefetchResponseBody` concatenates chunks into a single buffer to prevent `await` continuations from `createFromReadableStream` from interleaving between chunks, which would otherwise cause the root model row to initialize prematurely before promise value rows are processed [packages/next/src/client/components/segment-cache/cache.ts:3757-3765](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3757-L3765).

Sources: [packages/next/src/client/components/segment-cache/cache.ts:3757-3765](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/cache.ts#L3757-L3765)

### Navigation Seeds and Vary Parameter Resolution

When a response arrives, `createNavigationSeed` overlays the transport tree onto the existing base router state [packages/next/src/client/components/segment-cache/decode-server-response.ts:96-103](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L96-L103). It extracts the root vary parameters (`rootVaryParams`), unioning them into the head's and every segment's drained set at the decode boundary [packages/next/src/client/components/segment-cache/decode-server-response.ts:104-110](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L104-L110). Dynamic segments sent without a parameter value (`k: null`) are resolved by parsing the value from the rendered pathname using `resolveTransportSegment` and `parseDynamicParamFromURLPart` [packages/next/src/client/components/segment-cache/decode-server-response.ts:333-336](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L333-L336), [packages/next/src/client/components/segment-cache/decode-server-response.ts:369-396](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L369-L396).

```typescript
export type NavigationSeed = {
  renderedSearch: NormalizedSearch
  /**
   * The decoded response. The head's `data` is decoded exactly like a segment
   * node's: null when the response carries no head.
   */
  root: RootRouteTree<RSCSegmentData | null>
  dynamicStaleAt: number
  // Whether the response rendered a segment whose identity differs from the
  // base tree's at the same position (inactive parallel route branches are
  // expected to differ and don't count). Only meaningful when the base is a
  // request tree derived from a cached route entry, as during a prefetch:
  // divergence then means the entry doesn't describe what the server renders
  // — the URL has a rewrite that behaves dynamically (see
  // fetchSegmentPrefetchesUsingRuntimeRequest). During a navigation the base
  // is the current page's tree, so divergence carries no signal. False when
  // there was no base to compare against.
  treeDivergedFromBase: boolean
}
```
Sources: [packages/next/src/client/components/segment-cache/decode-server-response.ts:64-82](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L64-L82), [packages/next/src/client/components/segment-cache/decode-server-response.ts:96-110](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L96-L110), [packages/next/src/client/components/segment-cache/decode-server-response.ts:369-396](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L369-L396)

> [!WARNING]
> Boolean-form nodes evaluate `isPartial` using response-level partiality (`isResponsePartial`), because wire booleans act as render-wide constants that are inaccurate for static PPR pages or truncated stage decodes. Promise-form nodes instead rely strictly on `readFulfilledIsPartial`, where partialness is encoded as the absence of a fulfillment [packages/next/src/client/components/segment-cache/decode-server-response.ts:618-639](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L618-L639), [packages/next/src/client/components/segment-cache/decode-server-response.ts:673-675](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L673-L675).

Sources: [packages/next/src/client/components/segment-cache/decode-server-response.ts:618-639](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L618-L639), [packages/next/src/client/components/segment-cache/decode-server-response.ts:673-675](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/decode-server-response.ts#L673-L675)

## Back-Forward Cache State Management

### Back-Forward Cache Entry Structure and Versioning

Back-forward navigation and segment state preservation are coordinated through dedicated entries stored in the `bfcacheMap`. Each `BFCacheEntry` captures both server components and metadata associated with a completed navigation [packages/next/src/client/components/segment-cache/bfcache.ts:34-62](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L34-L62).

```typescript
export type BFCacheEntry = {
  rsc: React.ReactNode | null
  prefetchRsc: React.ReactNode | null

  // The source of the params `rsc` depends on, copied from the CacheNode that
  // wrote this entry (see CacheNode.varyParams). A restored node reads it to
  // decide whether a later navigation can keep its data.
  varyParams: VaryParams | null

  // The bfcacheId of the CacheNode that wrote this entry. Restored on
  // history-traversal navigations so that `useRouter().bfcacheId` is stable
  // across back/forward, even without `cacheComponents` Activity preservation.
  bfcacheId: number

  ref: UnknownMapEntry | null
  size: number
  // The time at which this data was received. Used to compute the stale time
  // for dynamic prefetches (which use STATIC_STALETIME_MS instead of
  // DYNAMIC_STALETIME_MS). Stored explicitly because staleAt may be
  // overridden by a per-page unstable_dynamicStaleTime, which would break
  // any reverse calculation from staleAt.
  navigatedAt: number
  staleAt: number
  version: number
  // A BFCacheEntry always represents a completed navigation, so the status is
  // always Fulfilled. The field exists so that BFCacheEntry conforms to the
  // MapValue protocol.
  status: EntryStatus.Fulfilled
}
```
Sources: [packages/next/src/client/components/segment-cache/bfcache.ts:34-62](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L34-L62)

> [!NOTE]
> `BFCacheEntry` instances store `size` using a fixed heuristic value (`100`) rather than exact byte measurement because segments reside within larger streaming payloads [packages/next/src/client/components/segment-cache/bfcache.ts:94-99](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L94-L99).

Sources: [packages/next/src/client/components/segment-cache/bfcache.ts:94-99](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L94-L99)

The following table details the fields maintained inside every `BFCacheEntry`:

| Field Name | Type | Description |
| :--- | :--- | :--- |
| `rsc` | `React.ReactNode \| null` | The primary rendered React node tree. |
| `prefetchRsc` | `React.ReactNode \| null` | The prefetch variant of the React node tree. |
| `varyParams` | `VaryParams \| null` | The source parameters that the `rsc` output depends on. |
| `bfcacheId` | `number` | Stable identifier of the `CacheNode` that authored the entry. |
| `ref` | `UnknownMapEntry \| null` | Internal reference pointer for the cache map layer. |
| `size` | `number` | Estimated entry footprint size (default heuristic `100`). |
| `navigatedAt` | `number` | Timestamp when the data was received, used for dynamic prefetch staleness. |
| `staleAt` | `number` | Absolute expiration timestamp determined by dynamic stale times. |
| `version` | `number` | Cache version tracking value matching `currentBfCacheVersion`. |
| `status` | `EntryStatus.Fulfilled` | Status indicator confirming the entry represents completed data. |

Sources: [packages/next/src/client/components/segment-cache/bfcache.ts:34-62](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L34-L62)

Invalidation of the back-forward cache is handled globally by incrementing `currentBfCacheVersion` via `invalidateBfCache()` when window contexts exist [packages/next/src/client/components/segment-cache/bfcache.ts:68-73](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L68-L73).

```typescript
export function invalidateBfCache(): void {
  if (typeof window === 'undefined') {
    return
  }
  currentBfCacheVersion++
}
```
Sources: [packages/next/src/client/components/segment-cache/bfcache.ts:68-73](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L68-L73)

### Stale Time Checks and Segment Restoration

Dynamic segment retention checks compute absolute stale timestamps using `computeDynamicStaleAt()`, which respects per-page `unstable_dynamicStaleTime` overrides sent via the server response `d` field or falls back to `DYNAMIC_STALETIME_MS` when `UnknownDynamicStaleTime` (`-1`) is present [packages/next/src/client/components/segment-cache/bfcache.ts:10-24](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L10-L24), [packages/next/src/client/components/segment-cache/bfcache.ts:132-136](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L132-L136).

```typescript
export function computeDynamicStaleAt(
  now: number,
  dynamicStaleTimeSeconds: number
): number {
  return dynamicStaleTimeSeconds !== UnknownDynamicStaleTime
    ? now + dynamicStaleTimeSeconds * 1000
    : now + DYNAMIC_STALETIME_MS
}
```
Sources: [packages/next/src/client/components/segment-cache/bfcache.ts:17-24](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L17-L24)

> [!CAUTION]
> During a history back/forward traversal navigation, `readFromBFCache` passes `-1` as the current time argument to `getFromCacheMap` in order to intentionally bypass staleness checks, allowing expired entries to be restored [packages/next/src/client/components/segment-cache/bfcache.ts:156-172](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L156-L172).

Sources: [packages/next/src/client/components/segment-cache/bfcache.ts:156-172](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L156-L172)

Regular navigations execute `readFromBFCacheDuringRegularNavigation()`, which evaluates the actual `now` timestamp against `staleAt` [packages/next/src/client/components/segment-cache/bfcache.ts:174-190](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L174-L190).

```typescript
export function readFromBFCacheDuringRegularNavigation(
  now: number,
  varyPath: VaryPath
): BFCacheEntry | null {
  if (typeof window === 'undefined') {
    return null
  }
  const isRevalidation = false
  return getFromCacheMap(
    now,
    currentBfCacheVersion,
    bfcacheMap,
    varyPath,
    isRevalidation,
    false
  )
}
```
Sources: [packages/next/src/client/components/segment-cache/bfcache.ts:174-190](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/segment-cache/bfcache.ts#L174-L190)

### Router Activity and Component Tree Preservation

The `useRouterBFCache` hook manages the retention of recent `FlightRouterStates` and render trees across segment level updates [packages/next/src/client/components/bfcache-state-manager.ts:38-42](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/bfcache-state-manager.ts#L38-L42). The maximum number of retained history entries is governed by `MAX_BF_CACHE_ENTRIES`, which evaluates to `3` when `__NEXT_CACHE_COMPONENTS` is enabled and `1` otherwise [packages/next/src/client/components/bfcache-state-manager.ts:8-10](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/bfcache-state-manager.ts#L8-L10).

Sources: [packages/next/src/client/components/bfcache-state-manager.ts:8-10](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/bfcache-state-manager.ts#L8-L10)

Entries inside the router back-forward state manager form a singly linked list sorted by most recently active order, utilizing copy-on-write cloning when traversing or inserting entries matching `stateKey` [packages/next/src/client/components/bfcache-state-manager.ts:11-17](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/bfcache-state-manager.ts#L11-L17), [packages/next/src/client/components/bfcache-state-manager.ts:71-116](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/bfcache-state-manager.ts#L71-L116).

Sources: [packages/next/src/client/components/bfcache-state-manager.ts:11-17](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/bfcache-state-manager.ts#L11-L17)

## Hydration Initialization and Invalidation

### Hydration Payload Population and Route Discovery

When the [client runtime](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/client-runtime) initializes, `createInitialRouterState` extracts metadata and transport data from the `InitialRSCPayload` [packages/next/src/client/components/router-reducer/create-initial-router-state.ts:28-45](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/create-initial-router-state.ts#L28-L45). The canonical URL is resolved from the initial parts array or window location, while the initial Flight router state is decoded from the transport tree using `transportNodeToFlightRouterState` [packages/next/src/client/components/router-reducer/create-initial-router-state.ts:47-56](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/create-initial-router-state.ts#L47-L56). 

```typescript
export function createInitialRouterState({
  navigatedAt,
  initialRSCPayload,
  initialFlightStreamForCache,
  location,
}: InitialRouterStateParameters): AppRouterState {
  const {
    c: initialCanonicalUrlParts,
    t: initialTransportData,
    q: initialRenderedSearch,
    i: initialCouldBeIntercepted,
    S: initialSupportsPerSegmentPrefetching,
    s: initialStaleTime,
    l: initialStaticStageByteLength,
    r: initialRootVaryParams,
    p: initialRuntimePrefetchStream,
    d: initialDynamicStaleTimeSeconds,
  } = initialRSCPayload

  // When initialized on the server, the canonical URL is provided as an array of parts.
  // This is to ensure that when the RSC payload streamed to the client, crawlers don't interpret it
  // as a URL that should be crawled.
  const initialCanonicalUrl = initialCanonicalUrlParts.join('/')

  // The initial router state tree, derived from the transport tree.
  const initialTree = transportNodeToFlightRouterState(
    initialTransportData.t,
    initialRenderedSearch
  )
```
Sources: [packages/next/src/client/components/router-reducer/create-initial-router-state.ts:28-56](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/create-initial-router-state.ts#L28-L56)

When executing in the browser (`location !== null`), `discoverKnownRoute` registers the current pathname, search parameters, intercepting flags, and rendered search into the route cache map for future navigation prediction [packages/next/src/client/components/router-reducer/create-initial-router-state.ts:108-124](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/create-initial-router-state.ts#L108-L124).

```typescript
// The following only applies in the browser (location !== null) since neither
// route learning nor segment cache state persists from SSR to client.
if (location !== null) {
  // Learn the route pattern so we can predict it for future navigations.
  discoverKnownRoute(
    Date.now(),
    location.pathname,
    location.search as NormalizedSearch,
    null, // nextUrl — initial render is never an interception
    null, // No pending entry
    initialRoot,
    initialCouldBeIntercepted,
    canonicalUrl,
    initialSeed.renderedSearch,
    initialSupportsPerSegmentPrefetching,
    false // hasDynamicRewrite
  )
```
Sources: [packages/next/src/client/components/router-reducer/create-initial-router-state.ts:108-124](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/create-initial-router-state.ts#L108-L124)

### Static Stage Caching and Stream Population

If an initial stale time is present, hydration writes payload data into the segment cache so subsequent navigations can serve segments instantly [packages/next/src/client/components/router-reducer/create-initial-router-state.ts:133-137](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b5

## Related

- [App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/app-router)
- [Router Reducer](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/router-reducer)


## Sitemap

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