This page provides a detailed technical overview of the React Flight wire protocol used for React Server Components (RSC). It covers the wire protocol for server-side serialization (ReactFlightServer), client-side deserialization (ReactFlightClient), the reply/action system, bundler integrations (Webpack, Turbopack, ESM, Parcel), and security considerations via the taint registry.
React Server Components (RSC) utilize a specialized wire protocol codenamed Flight to efficiently stream serialized React component trees and related data from the server to a client-rendering environment. This protocol enables React to pass component models and references between server and client, supporting features like Suspense, lazy loading, actions, and streaming updates.
Key concerns addressed by the Flight Protocol are:
REACT_ELEMENT_TYPE), fragments, lazy components, server references, and primitives into a special JSON-like or binary Flight protocol format. It handles a spectrum of React types including elements, fragments, and async iterators, ensuring that client references and server references are encoded properly.The ReactFlightServer module implements server-side functionality for serializing React Server Component payloads into a streamable format.
Serialization: It converts React elements (REACT_ELEMENT_TYPE), fragments, lazy components, server references, and primitives into the Flight protocol format. This serialization handles complex React structures including async iterators and references with metadata to support client-side rehydration and lazy boundaries.
Reference Management: Uses IDs and metadata to distinguish between client references (which represent client-side-only modules or components) and server references (serializable server functions with bound arguments). This allows serializing server references as lightweight handles that clients can use to invoke server actions.
Asynchronous Flow: Supports Suspense by intercepting Promises thrown during component rendering and async iteration. It streams placeholder chunks for suspended content, later replacing them with resolved data to support streaming updates and graceful fallback behavior.
Temporary References: Serializes transient objects as temporary references, preserving their identity across the Flight wire, and enabling correct client-side recreation to maintain referential equality where needed.
The server uses a Request abstraction to manage write destinations and the chunk queue. It supports atomic writing of serialized chunks to Node streams or Web Streams using utilities like writeChunk() and flushBuffered() packages/react-server/src/ReactFlightServer.js10-35
The server rendering employs a hook dispatcher (HooksDispatcher) from the ReactFlightHooks to correctly handle React hooks in the server environment packages/react-server/src/ReactFlightServer.js109-115
Async sequences and React's async components or Suspense boundaries are handled by ReactFlightAsyncSequence, which converts iterables and async iterables into resolvable streams of chunks packages/react-server/src/ReactFlightServer.js160-167
The server carefully filters stack traces for debugging and devirtualizes URLs for better source location identification, improving error diagnostics during serialization packages/react-server/src/ReactFlightServer.js171-245
Server Serialization Pipeline
Sources: packages/react-server/src/ReactFlightServer.js1-240 packages/react-server/src/ReactFlightAsyncSequence.js1-100
The ReactFlightClient module handles the reconstruction of the React component tree from the incoming Flight stream.
The client implements a state machine to parse the Flight protocol stream as a sequence of rows. Each chunk has a lifecycle managed through states:
PENDING: Chunk data has not yet arrived.BLOCKED: Chunk data arrived but awaiting resolution of dependencies or lazy boundaries.RESOLVED_MODEL: Serialized JSON-like flight payload is received but not yet parsed fully.INITIALIZED: Chunk has been parsed and instantiated into React elements or primitives.This lifecycle is managed using promises-like objects that resolve asynchronously as data arrives over the network stream.
The client parses incoming Flight stream rows using a parsable state machine with incremental row components: chunk ID, tag (identifying chunk type), length, and chunk data.
It uses string decoders (createStringDecoder) and chunk reading utilities (readPartialStringChunk, readFinalStringChunk) to process UTF-8 encoded JSON and other data from the stream.
Upon parsing, chunks can represent React models, client references, server references, or errors. References are resolved via configured mappings and client manifest information.
Temporary references are deserialized and restored to maintain identity and state shared across chunks.
The client supports lazy components, fragments, and async iterators, reconstructing them into React elements or Suspense boundaries dynamically.
Client Protocol Parsing and Resolution
Sources: packages/react-client/src/ReactFlightClient.js1-230 packages/react-client/src/ReactFlightClientConfig.js1-66 packages/react-client/src/ReactFlightTemporaryReferences.js1-20
Flight Protocol enables the client to invoke server-side functions (actions) securely. This is achieved through:
Server Reference Generation: Server-side functions are wrapped in serializable references with unique IDs (getServerReferenceId()), enabling lightweight transmission to the client as stubs packages/react-server/src/ReactFlightServer.js81
Client Proxy Creation: On the client, bound server references are presented as proxy functions generated by createBoundServerReference() which serialize call arguments and send them back to the server when invoked packages/react-client/src/ReactFlightReplyClient.js69-71
Client-to-Server Encoding: Arguments passed from the client for server calls are serialized into the Flight Reply payload using processReply(). It supports both JSON and FormData, allowing streaming of complex form-related data packages/react-client/src/ReactFlightReplyClient.js183-195
Server Execution and Response: On the server, the Flight Reply payload is decoded and dispatched using ReactFlightReplyServer, executing referenced server functions and streaming back the result as Flight payload packages/react-server/src/ReactFlightReplyServer.js217-220
processReply(), enabling smooth progressive enhancement when upgrading classical form submissions to React Server Component interactions.Sources:
Flight supports multiple bundlers to correctly handle client and server references for the protocol, integrating with the bundler's module graph.
| Bundler | Reference Implementation | Key Functionality |
|---|---|---|
| Webpack | ReactFlightWebpackReferences.js | Maps module IDs and handles export resolution |
| Turbopack | ReactFlightTurbopackReferences.js | Integrates with Turbopack's module and graph system |
| ESM | ReactFlightESMReferences.js | Resolves references via native URLs and import maps |
| Parcel | Parcel fork ReactFlightDOMClientNode.js | Node-specific client streaming integration |
Bundlers generate Client Manifests describing available client modules and Server Manifests describing server references (e.g., actions).
Webpack includes additional tooling:
ReactFlightWebpackPlugin.js hooks into bundling to generate manifests and assign IDs.ReactFlightWebpackNodeLoader.js manages runtime resolution using these manifests.Sources:
To prevent accidental or malicious leakage of sensitive server-side data (e.g., secrets, database handles) to the client, the Flight Protocol integrates a Taint Registry.
When the enableTaint feature flag is enabled, developers can mark objects as tainted on the server.
During serialization, all values are checked against this registry.
If a tainted value is detected to be serialized and sent to the client, the serialization process throws an error, preventing exposure of sensitive data.
This mechanism ensures data flows conform to security constraints imposed by the server environment.
Sources: packages/react-server/src/ReactFlightServer.js15-115
Flight Protocol embeds instrumentation hooks to track component-level performance on both server and client.
Server: Uses enableProfilerTimer and enableComponentPerformanceTrack flags for collecting and emitting profiling metadata during serialization, attaching profiling information to chunks.
Client: Implements logging functions (logComponentRender, logIOInfo) to track React component lifecycles and asynchronous I/O, feeding user timing APIs or devtools.
This data can be used for diagnostics and optimizing rendering performance of server components.
Performance Data Flow
Sources:
Sources:
Refresh this wiki