---
title: "RSC Transport"
description: "RSC Transport defines the wire formats, serialization schemas, and transport tree data structures used to transmit React Server Component responses between server renderers and client routers in Ne..."
last_updated: "2026-10-12T06:38:56.887958+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/rsc-transport"
---

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

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

- [packages/next/src/shared/lib/rsc-transport.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/shared/lib/rsc-transport.ts)
- [packages/next/src/server/app-render/action-handler.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/action-handler.ts)
- [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/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/app-index.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx)
- [packages/next/src/shared/lib/app-router-types.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/shared/lib/app-router-types.ts)
- [packages/next/src/server/app-render/use-flight-response.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/use-flight-response.tsx)
- [packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts)
- [packages/next/src/client/components/app-router-headers.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/components/app-router-headers.ts)
- [packages/next/src/server/app-render/instant-validation/instant-validation.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/instant-validation/instant-validation.tsx)
- [packages/next/src/client/flight-data-helpers.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/flight-data-helpers.ts)
- [packages/next/src/server/app-render/encryption.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/encryption.ts)
- [packages/next/src/server/app-render/stream-ops.node.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/stream-ops.node.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/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/server/app-render/create-component-tree.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/create-component-tree.tsx)
- [packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts)
- [packages/next/src/server/app-render/dev-validation-error-delivery.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dev-validation-error-delivery.ts)
- [packages/next/src/server/dev/serialized-errors.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/serialized-errors.ts)
- [packages/next/src/build/webpack/loaders/next-flight-loader/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/loaders/next-flight-loader/index.ts)
- [packages/next/src/server/app-render/react-server.node.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/react-server.node.ts)
- [packages/next/src/server/app-render/flight-render-result.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/flight-render-result.ts)
- [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)
</details>

## Overview

RSC Transport defines the wire formats, serialization schemas, and transport tree data structures used to transmit React Server Component responses between server renderers and client routers in Next.js. It bridges server-side component tree generation with client-side ingestion, establishing the wire conventions for [Segment Cache](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/segment-cache), [Router Reducer](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/router-reducer), and [App Rendering](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/app-rendering).

Sources: [packages/next/src/shared/lib/rsc-transport.ts:1-15](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/shared/lib/rsc-transport.ts#L1-L15)

## Transport Protocol and Data Structures

### Transport Node Representation

The transport protocol governs how React Server Component payloads are structured, serialized, and mapped between server renderers and client routers. Every transport type is prefixed with `Transport` to distinguish the wire format from client-local types like `Segment`, `RouteTree`, `CacheNode`, and `FlightRouterState`, ensuring client code converts out of transport types at the decode boundary and never stores them directly.

Tree payloads are represented as hierarchical node structures (`FullTransportNode` and `PartialTransportNode`) built around a shared node shape (`TransportNodeShape`). Full response trees account for every node in the route segment hierarchy, whereas partial trees act as overlays produced during navigations, refreshes, and [server actions](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/server-actions). Parallel routes are structured using `Map` instances for child slots rather than plain objects to prevent megamorphic keyed access caused by hidden class variations across app-defined slot names.

| Transport Node Field | Type | Description |
| :--- | :--- | :--- |
| `s` | `TransportSegment` | The wire segment identity for the route node. |
| `d` | `TransportSegmentData` (or optional `d?`) | Segment output data; always present in full nodes, optional in partial nodes. |
| `c` | `Map<string, Node>` (or optional) | Parallel route child slots, stored as a `Map` of slot keys to transport nodes. |
| `h` | `TransportSegmentData` (or optional) | Segment-level head metadata (such as title or meta tags). |

Sources: [packages/next/src/shared/lib/rsc-transport.ts:136-179](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/shared/lib/rsc-transport.ts#L136-L179)

> [!NOTE]
> `FullTransportNode` is structurally assignable to `PartialTransportNode`, allowing the union type `TransportNode` to collapse to `PartialTransportNode` for the TypeScript type checker while retaining the union spelling to document developer intent.

Sources: [packages/next/src/shared/lib/rsc-transport.ts:181-188](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/shared/lib/rsc-transport.ts#L181-L188)

### Segment Encoding and Conversion

Route segments alternate between internal representations and wire representations. A segment is encoded as either a plain string (for static segments or special keys like `PAGE_SEGMENT_KEY`) or an object carrying compressed property keys: `n` for the parameter name, `t` for the parameter type, `k` for the parameter cache key, and `s` for static siblings.

```typescript
export type TransportSegment =
  | string
  | {
      n: string
      t: string
      k: string | null
      s: string
    }
```

Sources: [packages/next/src/shared/lib/rsc-transport.ts:259-296](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/shared/lib/rsc-transport.ts#L259-L296)

When processing fallback prerenders where dynamic parameters are absent from the initial static shell, the client patches the transport tree by parsing parameter values directly from the rendered pathname and populating missing cache keys via `fillInFallbackTransportTree`.

```typescript
function fillInFallbackTransportTree(
  node: FullTransportNode,
  pathnameParts: Array<string>,
  pathnamePartsIndex: number
): FullTransportNode {
  const originalSegment = node.s
  let newSegment: TransportSegment
  let doesAppearInURL: boolean
  if (typeof originalSegment === 'string') {
    newSegment = originalSegment
    doesAppearInURL = doesStaticSegmentAppearInURL(originalSegment)
  } else {
    const paramValue = parseDynamicParamFromURLPart(
      originalSegment.t,
      pathnameParts,
      pathnamePartsIndex
    )
    newSegment = {
      n: originalSegment.n,
      t: originalSegment.t,
      k: getCacheKeyForDynamicParam(paramValue),
      s: originalSegment.s,
    }
    doesAppearInURL = true
  }
```
Sources: [packages/next/src/client/flight-data-helpers.ts:77-101](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/flight-data-helpers.ts#L77-L101)

## Flight Streaming and Response Generation

### Flight Stream Decoding and Consumer Manifests

Server-side construction of Flight data streams involves wrapping raw React Server Component outputs into specialized render results and processing streams through `react-server-dom-webpack` client deserializers. The `getFlightStream` function retrieves or initializes responses from either Node.js readable streams or Web `ReadableStream` instances. Client reference manifests supply module mapping metadata—selecting `edgeSSRModuleMapping` for the [edge runtime](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/edge-runtime) or `ssrModuleMapping` for Node.js servers, alongside client module loading configurations and debug channels.

```typescript
export function getFlightStream<T>(
  flightStream: Readable | BinaryStreamOf<T>,
  debugStream: Readable | ReadableStream<Uint8Array> | undefined,
  debugEndTime: number | undefined,
  nonce: string | undefined
): Promise<T>
```

Sources: [packages/next/src/server/app-render/use-flight-response.tsx:35-40](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/use-flight-response.tsx#L35-L40)

> [!NOTE]
> When executing under client-side prerendering or validation work units in non-edge runtimes, responses are deferred to the next tick via `process.nextTick` before being stored in the `flightResponses` `WeakMap`.

Sources: [packages/next/src/server/app-render/use-flight-response.tsx:119-135](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/use-flight-response.tsx#L119-L135)

### Inlined Data Streams and Payload Instructions

To transmit hydration data and incremental payload chunks outside the core React tree render, `createInlinedDataReadableStream` constructs a lazy Web `ReadableStream` that outputs inline script tag blocks. Initial bootstrap instructions, form states, and flight data payloads are serialized into JSON arrays, escaped, and pushed into the global `self.__next_f` array.

| Payload Constant | Numeric Value | Description |
| :--- | :--- | :--- |
| `INLINE_FLIGHT_PAYLOAD_BOOTSTRAP` | `0` | Initializes the global `self.__next_f` stream buffer. |
| `INLINE_FLIGHT_PAYLOAD_DATA` | `1` | Transmits stringified Flight text chunks. |
| `INLINE_FLIGHT_PAYLOAD_FORM_STATE` | `2` | Supplies initial form state data. |
| `INLINE_FLIGHT_PAYLOAD_BINARY` | `3` | Transmits binary chunks encoded in base64 when UTF-8 decoding fails. |

Sources: [packages/next/src/server/app-render/use-flight-response.tsx:14-18](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/use-flight-response.tsx#L14-L18), [packages/next/src/server/app-render/use-flight-response.tsx:221-237](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/use-flight-response.tsx#L221-L237)

Binary chunks that cannot be embedded directly as valid UTF-8 strings are converted to base64 strings using `Buffer.from` or `btoa` before being bundled into instruction arrays.

```tsx
  const base64 =
    typeof Buffer !== 'undefined'
      ? Buffer.from(
          chunk.buffer,
          chunk.byteOffset,
          chunk.byteLength
        ).toString('base64')
      : btoa(String.fromCodePoint(...chunk))
  htmlInlinedData = htmlEscapeJsonString(
    JSON.stringify([INLINE_FLIGHT_PAYLOAD_BINARY, base64])
  )
}
```
Sources: [packages/next/src/server/app-render/use-flight-response.tsx:255-266](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/use-flight-response.tsx#L255-L266)

### Response Wrapping and Content Types

Completed Flight streams are wrapped into custom `RenderResult` subclasses to guarantee correct HTTP header assignment. `FlightRenderResult` forces the response content type header to match `RSC_CONTENT_TYPE_HEADER`, preventing downstream proxies or browsers from misinterpreting binary RSC payloads as HTML documents.

```typescript
export class FlightRenderResult extends RenderResult {
  constructor(
    response: string | AnyStream,
    metadata: RenderResultMetadata = {},
    waitUntil?: Promise<unknown>
  ) {
    super(response, {
      contentType: RSC_CONTENT_TYPE_HEADER,
      metadata,
      waitUntil,
    })
  }
}
```

Sources: [packages/next/src/server/app-render/flight-render-result.ts:8-19](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/flight-render-result.ts#L8-L19)

## Client Reference and Action Manifests

### Compiler Identification and Module Mapping

During the build process, the Flight client entry plugin traverses Webpack compilation chunks to identify client components and server actions, recording their module identifiers and chunk associations. The plugin creates asset manifests that map server actions and client entries for both Node.js and edge runtime targets, assigning metadata such as async status and browser or server layers.

Sources: [packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts:1110-1137](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L1110-L1137)

### Action Manifests and Asset Emission

Server actions are collected into runtime-specific structures (`serverActions` and `edgeServerActions`), linking action identifiers to their worker module IDs depending on whether their layer matches `WEBPACK_LAYERS.actionBrowser`. The resulting manifests are serialized to JSON and emitted as assets, alongside a JavaScript wrapper assigned to `self.__RSC_SERVER_MANIFEST`.

Sources: [packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts:1139-1190](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L1139-L1190)

> [!NOTE]
> Edge server manifests override the encryption key property with the string literal `'process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY'` rather than embedding the build-time static secret directly.

Sources: [packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts:1168-1171](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L1168-L1171)

### Module Resource Resolution and Import Collection

Module paths are normalized using resolved resource data and query parameters to ensure client and server compilers share identical paths. For CommonJS modules, default imports automatically include the `__esModule` identifier alongside requested names to guarantee compatibility with React's client module proxy layer.

```typescript
function getModuleResource(mod: webpack.NormalModule): string {
  const modPath: string = mod.resourceResolveData?.path || ''
  const modQuery = mod.resourceResolveData?.query || ''
  // We have to always use the resolved request here to make sure the
  // server and client are using the same module path (required by RSC), as
  // the server compiler and client compiler have different resolve configs.
  let modResource: string = modPath + modQuery

  // Context modules don't have a resource path, we use the identifier instead.
  if (mod.constructor.name === 'ContextModule') {
    modResource = mod.identifier()
  }

  // For the barrel optimization, we need to use the match resource instead
  // because there will be 2 modules for the same file (same resource path)
  // but they're different modules and can't be deduped via `visitedModule`.
  // The first module is a virtual re-export module created by the loader.
  if (mod.matchResource?.startsWith(BARREL_OPTIMIZATION_PREFIX)) {
    modResource = mod.matchResource + ':' + modResource
  }

  if (mod.resource === `?${WEBPACK_RESOURCE_QUERIES.metadataRoute}`) {
    return getMetadataRouteResource(mod.rawRequest).filePath
  }

  return modResource
}
```
Sources: [packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts:1239-1265](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L1239-L1265)

## Action Bound Argument Cryptographic Serialization

### Bound Argument Encryption and Caching

Server action bound arguments are serialized through React Flight via `renderToReadableStream`, capturing arguments into a string payload before cryptographic operations. To guarantee reference equality for objects returned from "use cache" functions when invoked repeatedly within a single render pass, `encryptActionBoundArgs` is wrapped in `React.cache`. A cache key is constructed by combining the `actionId` and the serialized argument string, allowing lookup and reuse of previously encrypted arguments from `resumeDataCache?.encryptedBoundArgs`.

```typescript
export const encryptActionBoundArgs = React.cache(
  async function encryptActionBoundArgs(actionId: string, ...args: any[]) {
    const workUnitStore = workUnitAsyncStorage.getStore()
    const cacheSignal = workUnitStore
      ? getCacheSignal(workUnitStore)
      : undefined

    const { clientModules } = getClientReferenceManifest()
```
Sources: [packages/next/src/server/app-render/encryption.ts:108-115](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/encryption.ts#L108-L115)

```typescript
  const cacheKey = actionId + serialized

  const cachedEncrypted = resumeDataCache?.encryptedBoundArgs.get(cacheKey)

  if (cachedEncrypted) {
    return cachedEncrypted
  }

  const encrypted = await encodeActionBoundArg(actionId, serialized)

  endReadIfStarted()
  if (resumeDataCache?.mutable) {
    resumeDataCache.encryptedBoundArgs.set(cacheKey, encrypted)
  }

  return encrypted
}
```
Sources: [packages/next/src/server/app-render/encryption.ts:223-239](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/encryption.ts#L223-L239)

> [!NOTE]
> During development mode in cache components, a dummy debug channel consisting of an empty `WritableStream` is passed to `renderToReadableStream` to strip timing information from debug output. This prevents build/render timestamps from invalidating the cache key.

Sources: [packages/next/src/server/app-render/encryption.ts:164-179](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/encryption.ts#L164-L179)

### Decryption and Stream Hydration WorkUnits

Decryption reverses the pipeline by fetching cached or newly decoded argument strings using `decryptActionBoundArgs`. The decrypted string is fed into `createFromReadableStream` via a custom `ReadableStream` controller. Depending on the active work unit store type, stream closure behavior is adjusted to handle hanging promises or immediate termination.

| Work Unit Store Type | Controller Termination Behavior | Sources |
| :--- | :--- | :--- |
| `prerender`, `prerender-runtime` | Defers stream closure until prerendering completes or `renderSignal` aborts. | [packages/next/src/server/app-render/encryption.ts:279-293](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/encryption.ts#L279-L293) |
| `prerender-client`, `validation-client`, `prerender-legacy`, `request`, `cache`, `private-cache`, `unstable-cache`, `build-time-generator`, `undefined` | Closes the controller immediately via `controller.close()`. | [packages/next/src/server/app-render/encryption.ts:294-303](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/encryption.ts#L294-L303) |

Sources: [packages/next/src/server/app-render/encryption.ts:274-307](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/encryption.ts#L274-L307)

## Client Ingestion and Stream Hydration

### Browser-Side Bootstrapping and Inline Script Parsing

The client-side [App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/app-router) bootstraps by evaluating `app-index.tsx`, which interacts with the global `self.__next_f` array to ingest initial Flight data pushed during server-side rendering. Chunks are dispatched into `nextServerDataLoadingGlobal` using a tuple-based `FlightSegment` schema.

| Segment Opcode (`seg[0]`) | Payload Type | Description | Sources |
| :--- | :--- | :--- | :--- |
| `0` | None | Initializes `initialServerDataBuffer = []` to collect subsequent chunks. | [packages/next/src/client/app-index.tsx:81-83](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L81-L83) |
| `1` | `string` | Enqueues raw text data or pushes it to the server data buffer. | [packages/next/src/client/app-index.tsx:84-92](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L84-L92) |
| `2` | `any` | Assigns form state data to `initialFormStateData`. | [packages/next/src/client/app-index.tsx:93-94](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L93-L94) |
| `3` | `string` (Base64) | Decodes Base64-encoded binary chunks into `Uint8Array` arrays. | [packages/next/src/client/app-index.tsx:95-111](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L95-L111) |

Sources: [packages/next/src/client/app-index.tsx:60-112](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L60-L112)

> [!WARNING]
> If a chunk with opcode `1` or `3` arrives before opcode `0` has initialized `initialServerDataBuffer`, `nextServerDataCallback` throws an error stating that the bootstrap script is missing.

Sources: [packages/next/src/client/app-index.tsx:84-86](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L84-L86), [packages/next/src/client/app-index.tsx:96-97](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L96-L97)

### React Flight Response Consumption

Once the initialization chunks are collected, a `ReadableStream` is constructed to feed React via `nextServerDataRegisterWriter`. When `DOMContentLoaded` fires, any pending writers are closed to finalize hydration.

```tsx
function nextServerDataRegisterWriter(ctr: ReadableStreamDefaultController) {
  if (initialServerDataBuffer) {
    initialServerDataBuffer.forEach((val) => {
      ctr.enqueue(typeof val === 'string' ? encoder.encode(val) : val)
    })
    if (initialServerDataLoaded && !initialServerDataFlushed) {
      // Instant Navigation Testing API: don't close or error the inline
      // Flight stream. The static shell has no inline Flight data, so the
      // stream is empty. Closing it would cause React to log an error about
      // missing data. Leaving it open lets React treat any holes as
      // "still suspended." Hydration uses the separately fetched RSC payload
      // (self.__next_instant_test), not this stream.
      if (isStreamErrorOrUnfinished(ctr)) {
        if (!instantTestStaticFetch) {
          ctr.error(
            new Error(
              'The connection to the page was unexpectedly closed, possibly due to the stop button being clicked, loss of Wi-Fi, or an unstable internet connection.'
            )
          )
        }
      } else {
        ctr.close()
      }
      initialServerDataFlushed = true
      initialServerDataBuffer = undefined
    }
  }

  initialServerDataWriter = ctr
}
```
Sources: [packages/next/src/client/app-index.tsx:127-156](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L127-L156)

> [!NOTE]
> When cache components and experimental cached navigations are enabled, the hydration stream is teed into two branches: one for React consumption and one for caching purposes.

Sources: [packages/next/src/client/app-index.tsx:200-208](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/client/app-index.tsx#L200-L208)

## Segment Prefetch Payload Packaging

### Tree Construction and Identity Spine Wrapping

Segment prefetch payloads are built by constructing a root-anchored transport tree starting from the terminal segment and wrapping upward along the identity spine. Each ancestor node along the spine is linked via its parallel route key, carrying its own prefetch hints if non-zero. If prefetching is disabled for an ancestor, its segment data is omitted, leaving it with identity information only so the client treats it as a non-claimable node.

```tsx
let node: PartialTransportNode = { s: spine.segment }
if (spine.prefetchHints !== 0) {
  node.h = spine.prefetchHints
}
if (terminal !== null) {
  node.d = createStagedSegmentData(
    terminal,
    staleTime,
    clientModules,
    streamInfoStage.promise
  )
}
let edgeParallelRouteKey = spine.parallelRouteKey
let ancestor = spine.parent
let bundleNode = bundle
while (ancestor !== null && edgeParallelRouteKey !== null) {
  const parentNode: PartialTransportNode = {
    s: ancestor.segment,
  }
  if (ancestor.prefetchHints !== 0) {
    parentNode.h = ancestor.prefetchHints
  }
  if (bundleNode !== null) {
    if (bundleNode.data !== null) {
      parentNode.d = createStagedSegmentData(
        bundleNode.data,
        staleTime,
        clientModules,
        streamInfoStage.promise
      )
    }
    bundleNode = bundleNode.next
  }
  parentNode.c = new Map([[edgeParallelRouteKey, node]])
  node = parentNode
  edgeParallelRouteKey = ancestor.parallelRouteKey
  ancestor = ancestor.parent
}
```
Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:1227-1264](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1227-L1264)

> [!NOTE]
> Root segment request keys are automatically normalized to `/_index` when packaging transport data, while non-root keys retain their original request identifiers.

Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:1275-1279](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1275-L1279)

### Prefetch Payload Structure and Stream Encapsulation

The assembled transport data is wrapped inside a `PrefetchFlightResponse` payload object alongside shell boundary offsets, runtime flags, and build identifiers before being rendered into a readable stream. Chunks emitted by the renderer are consumed asynchronously into an array while tracking the total byte length to determine the exact shell boundary offset.

| Payload Field | Type | Description | Sources |
| :--- | :--- | :--- | :--- |
| `t` | `PartialTransportData` | The wrapped transport tree and optional head data. | [packages/next/src/server/app-render/collect-segment-data.tsx:1288](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1288) |
| `a` | `Promise<number \| null>` | Resolves to the byte length after the shell stage or `null` if the shell is a full response. | [packages/next/src/server/app-render/collect-segment-data.tsx:1289](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1289) |
| `u` | `Promise<boolean>` | Indicates whether a runtime request is needed. | [packages/next/src/server/app-render/collect-segment-data.tsx:1290](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1290) |
| `b` | `string` | Optional build identifier. | [packages/next/src/server/app-render/collect-segment-data.tsx:1292-1294](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1292-L1294) |
| `r` | `VaryParamsIterable` | Optional root vary parameters. | [packages/next/src/server/app-render/collect-segment-data.tsx:1295-1297](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1295-L1297) |
| `f` | `boolean` | Flag set when the payload represents an upgradeable ISR fallback. | [packages/next/src/server/app-render/collect-segment-data.tsx:1298-1300](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1298-L1300) |

Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:1287-1301](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1287-L1301)

> [!WARNING]
> If the abort signal fires during stream consumption, error rows emitted by the abort action are explicitly discarded to match prerender halting behavior.

Sources: [packages/next/src/server/app-render/collect-segment-data.tsx:1333-1338](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/collect-segment-data.tsx#L1333-L1338)

## Development Validation Error Transmission

### Flight-Encoded Error Serialization

When development validation errors occur during component rendering or validation worker execution, they are serialized into Flight protocol bytes using `serializeValidationErrorsToFlight`. This function retrieves client modules via `getClientReferenceManifest` and invokes `renderToNodeFlightStream` passing the component module, an errors object wrapper, client modules, and stack frame filters active outside production.

```typescript
export async function serializeValidationErrorsToFlight(
  componentMod: AppPageModule,
  errors: Error[]
): Promise<Uint8Array[]> {
  const { clientModules } = getClientReferenceManifest()

  const stream = renderToNodeFlightStream(
    componentMod,
    { errors },
    clientModules,
    { filterStackFrame }
  )

  const chunks: Uint8Array[] = []
  for await (const chunk of stream) {
    chunks.push(chunk)
  }
  return chunks
```
Sources: [packages/next/src/server/app-render/dev-validation-error-delivery.ts:18-35](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dev-validation-error-delivery.ts#L18-L35)

> [!WARNING]
> Serialization must execute in the runtime that originally generated the errors—such as an in-process render or a validation worker—to ensure matching client-reference manifests capture live `Error` instances complete with stacks and digests.

Sources: [packages/next/src/server/app-render/dev-validation-error-delivery.ts:11-17](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/dev-validation-error-delivery.ts#L11-L17)

### HMR Delivery and Stream Management

Serialized error streams are tracked in memory using `errorsRscStreamsByHtmlRequestId` as a mapping from HTML request identifiers to active stream instances. The Hot Module Replacement (HMR) layer interacts with this registry through dedicated lifecycle functions to transmit error payloads to the browser overlay.

| Function Name | Parameters | Description | Sources |
| :--- | :--- | :--- | :--- |
| `sendSerializedErrorsToClient` | `errorsRscStream: AnyStream`, `sendToClient: (message: HmrMessageSentToBrowser) => void` | Converts the RSC stream to a `Uint8Array` and dispatches an `ERRORS_TO_SHOW_IN_BROWSER` HMR message. | [packages/next/src/server/dev/serialized-errors.ts:10-25](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/serialized-errors.ts#L10-L25) |
| `sendSerializedErrorsToClientForHtmlRequest` | `htmlRequestId: string`, `sendToClient: (message: HmrMessageSentToBrowser) => void` | Looks up and deletes the error stream for a request ID, then dispatches it. | [packages/next/src/server/dev/serialized-errors.ts:27-40](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/serialized-errors.ts#L27-L40) |
| `setErrorsRscStreamForHtmlRequest` | `htmlRequestId: string`, `errorsRscStream: AnyStream` | Stores an error stream against an HTML request ID. | [packages/next/src/server/dev/serialized-errors.ts:42-49](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/serialized-errors.ts#L42-L49) |
| `deleteErrorsRscStreamForHtmlRequest` | `htmlRequestId: string` | Deletes the error stream entry for a given request ID. | [packages/next/src/server/dev/serialized-errors.ts:51-53](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/serialized-errors.ts#L51-L53) |

Sources: [packages/next/src/server/dev/serialized-errors.ts:10-53](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/dev/serialized-errors.ts#L10-L53)

## Related

- [App Rendering](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/app-rendering)
- [Server Actions](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/server-actions)
- [App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/app-router)


## Sitemap

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