facebook/react
react-server-dom-* packages
Active contributors: sebmarkbage, unstubbable, gnoff
Purpose
The react-server-dom-* packages are the bundler-specific clients and servers for React Server Components (RSC). All of them share the same Flight wire format (defined in react-server) but differ in how they interpret client references and server references — i.e. how they map Flight payload entries to the actual JS modules and how they package functions for round-tripping.
There are seven of them:
| Package | Purpose |
|---|---|
react-server-dom-webpack |
webpack bindings (Node + Edge runtimes). The most-used in the ecosystem; what Next.js uses. |
react-server-dom-parcel |
Parcel bindings. |
react-server-dom-turbopack |
Turbopack bindings. Next.js's newer bundler. |
react-server-dom-esm |
Pure-ESM bindings — the bundler is the browser/Node import resolver. |
react-server-dom-unbundled |
Like esm but with no module resolution at all; the user provides client/server reference resolvers. |
react-server-dom-fb |
Facebook-internal bundler (Metro / Wave). |
react-flight-server-fb |
New as of #36309 — the Facebook-specific Flight server, separate from the client. |
Plus react-markup, which renders an RSC tree to a string of markup rather than streaming it.
What's the same
Every package wraps react-server (for the writer) and react-client (for the reader) and exposes:
renderToPipeableStream(model, manifest, opts?)/renderToReadableStream(...)— Flight writer entry. Takes a React element (or a thenable for one) and a bundler manifest.createFromFetch(promise, opts?)/createFromReadableStream(stream, opts?)/createFromNodeStream(...)— Flight reader entry. Returns a React element you can render.decodeReply(body, manifest, opts?)/decodeReplyFromAsyncIterable(...)— Server Actions reply decoder.decodeAction(body, manifest)/decodeFormState(action, formState, manifest)— bridge from afetchresponse to a callable action.registerServerReference(fn, id, exportName)/registerClientReference(...)— runtime APIs for marking modules as server- or client-only when the bundler can't.
The shared client runtime is in packages/react-client/src/ReactFlightClient.js (~3,000 lines).
What differs
The bundler-specific code lives in each package's src/:
<pkg>/src/ReactFlightDOMClient<Variant>.js— the user-facing reader.<pkg>/src/ReactFlightDOMServer<Variant>.js— the user-facing writer.<pkg>/src/ReactFlightServerConfig<Pkg>.js— pluggable config for the writer (how to resolve client references).<pkg>/src/ReactFlightClientConfig<Pkg>.js— pluggable config for the reader (how to load a client reference).<pkg>/src/loaders/— bundler plugins (webpack loader, Parcel transformer, etc.).
Examples:
packages/react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack.js— knows how to look up an entry in webpack's__webpack_require__and friends.packages/react-server-dom-parcel/src/ReactFlightClientConfigBundlerParcel.js— same idea, but for Parcel's runtime.packages/react-server-dom-turbopack/src/loaders/RSDWClientLoader.js— Turbopack loader.
Server Actions
Server Actions are server functions you can call directly from the client. The flow:
sequenceDiagram
participant Client as Client (browser)
participant Bundler as Bundler runtime
participant Server as RSC server
Server->>Client: Flight payload row "F123" (server reference)
Client->>Bundler: form action="$action123" or onClick={action}
Client->>Server: POST /action123 (multipart with serialized args)
Server->>Server: ReactFlightReplyServer decodes args
Server->>Server: invoke the bound function
Server->>Client: Flight stream (return value)
Client->>Client: createFromReadableStream → React element / valueThe encoder/decoder pair is intentionally symmetric. Each package supplies its own way of identifying a function (webpack chunk + export, parcel asset id, turbopack module name, etc.).
Directory layout (typical, using react-server-dom-webpack)
packages/react-server-dom-webpack/
├── package.json
├── client.js / client.browser.js / client.edge.js / client.node.js
├── server.js / server.browser.js / server.edge.js / server.node.js
├── server.unbundled.js
├── static.js / static.edge.js / static.node.js
├── node-loader.js / node-register.js
└── src/
├── ReactFlightDOMClient.js # createFromFetch / createFromReadableStream
├── ReactFlightDOMClientNode.js / Edge.js / Browser.js
├── ReactFlightDOMServer.js # renderToReadableStream / renderToPipeableStream
├── ReactFlightDOMServerNode.js / Edge.js
├── ReactFlightClientConfigBundlerWebpack.js # how to resolve a client reference
├── ReactFlightServerConfigBundlerWebpack.js
├── ReactFlightClientConfig{Browser,Edge,Node}.js
├── ReactFlightServerConfig{Edge,Node}.js
└── loaders/ # webpack loader + entry pluginsHow to choose
If you are writing a framework, you pick the package that matches your bundler. If you are writing a bundler, you have two options:
- Implement webpack-compatible manifests (or parcel/turbopack-compatible). Use the matching
react-server-dom-*package. - Use
react-server-dom-unbundledand supply your ownloadClientReference/prepareDestinationForModulecallbacks. This is what Vite's RSC plugin and several research bundlers do.
Related pages
- react-server — the shared writer/reader infrastructure.
- features/server-components — the user-facing pipeline.
packages/react-client/src/ReactFlightClient.js— the bulk of the client decoder logic.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.