Open-Source Wikis

/

React

/

Features

/

Server Components

facebook/react

Server Components

React Server Components (RSC) are components that run on the server (or at build time) and produce a streamed Flight payload. The client never receives their source, only the result of running them, plus references to whichever client components the result depends on. The whole pipeline spans react-server, react-client, every react-server-dom-* package, and the react-server export condition in react/react-dom.

End-to-end pipeline

graph LR
  subgraph Server (RSC)
    Tree[App.server.js renders <App/>] -->|elements| Writer[react-server: ReactFlightServer]
    Writer -->|wire format| Stream[(stream)]
  end
  Stream -->|response body| Client[Browser]
  subgraph Client
    Reader[react-server-dom-*: createFromFetch] -->|model| Renderer[react-dom: createRoot]
    Renderer -->|hydrate| DOM[(DOM)]
    UserClick[user clicks <form>] -->|action invocation| Action[bundler-encoded server reference]
    Action -->|POST request| Server2[server endpoint]
    Server2 -->|new Flight stream| Reader
  end

Fizz (HTML SSR) and Flight (RSC payload) typically run together: Fizz produces the initial HTML; Flight produces the wire-format chunks the client uses to hydrate and to fetch updated regions.

Key files

Server side

  • packages/react-server/src/ReactFlightServer.js (~6,800 lines) — the Flight writer. Walks the React tree, serializes elements, encodes client/server references, manages the streaming queue.
  • packages/react-server/src/ReactFlightHooks.js — the dispatcher used during RSC rendering. Most client hooks throw; only a handful are allowed.
  • packages/react-server/src/ReactFlightActionServer.js — Server Actions on the server side. Decodes form bodies and invokes the bound function.
  • packages/react-server/src/ReactFlightReplyServer.js (~58,000 chars) — decodes form-data / multipart bodies sent back from the client. The "request" half of Server Actions.
  • packages/react-server/src/ReactFlightServerTemporaryReferences.js — round-trips opaque values (thenables, certain objects) without giving them stable ids.
  • packages/react-server/src/ReactFlightServerConfig.js — the bundler-pluggable config. Resolved per bundler at build time.

Client side

  • packages/react-client/src/ReactFlightClient.js (~3,000 lines) — the wire-format decoder. Allocates promise-backed chunk records; resolves them as the stream produces rows.
  • packages/react-server-dom-webpack/src/ReactFlightDOMClient.js (and Edge / Node siblings) — the user-facing reader: createFromFetch, createFromReadableStream, createFromNodeStream. Re-exports decodeReply, decodeAction, decodeFormState.
  • packages/react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack.js (and Parcel / Turbopack / ESM siblings) — the bundler-specific resolver: given a "module reference" id, how do you load the actual JS module?

Wire format

The Flight wire format is line-delimited and self-describing. Each line is <id>:<tag><payload>\n. Tags include:

  • J — model (a serialized React tree fragment).
  • I — module / client reference (an entry in the bundler manifest).
  • H — hint (preload directive).
  • D — debug info (development only).
  • E — error.
  • T — text chunk.
  • K — postpone (Fizz partial pre-rendering).
  • F — server reference (a function the client can call back).
  • B — Blob.
  • P — promise.
  • (and many more — the full table is at the top of ReactFlightServer.js.)

The format is append-only: the server keeps streaming as long as work remains, and the client decodes incrementally without waiting for the whole tree.

Client vs server modules

Each module in an RSC app is one of three things:

Kind Marker What's encoded in the stream
Server-only default Inlined in the Flight payload as serialized data. The source never reaches the client.
Client component "use client" directive at top of file Encoded as a client reference — a (chunk, name) pointer the bundler resolves. The client downloads it.
Server function (Action) "use server" directive Encoded as a server reference — a callable handle that, when invoked, hits a server endpoint.

The bundler is responsible for honoring the directives. Each react-server-dom-* package's loader (packages/react-server-dom-webpack/src/loaders/, react-server-dom-parcel's plugin, react-server-dom-turbopack's loader) implements the rewrite. registerClientReference/registerServerReference are runtime escape hatches if the bundler can't.

Server Actions

A "use server" function is a function the client can invoke directly. The bundler:

  1. Strips its body and replaces it with a server reference handle.
  2. The handle, when called from the client, serializes its arguments using react-client's reply encoder and POSTs to a server endpoint.
  3. The server's HTTP handler invokes decodeAction(body, manifest) from the matching react-server-dom-* package, which uses ReactFlightReplyServer.js to decode the body, then calls the bound function with the decoded args.
  4. The function's return value (or thrown error) is streamed back as another Flight payload.
  5. The client decodes it via the normal createFromReadableStream path and applies the result.

This is why Server Actions can be used inside <form action={action}> — the action is encoded as a stable URL with an opaque id, and the form POST flows through the same pipeline.

Hoistable resources and Server Components

When an RSC tree includes a <title>, a <link rel="stylesheet">, or an async <script>, the Float system (in packages/react-dom-bindings/src/server/ReactDOMFloatServer.js) emits resource hints in the Flight stream so the client can preload them before the corresponding component renders. The matching client-side code in packages/react-dom-bindings/src/client/ReactDOMFloatClient.js then promotes them into <head>.

How Fizz and Flight fit together

A typical Next.js-style request flow:

  1. The framework calls Flight: renderToReadableStream(<App/>, manifest).
  2. The framework also calls Fizz: renderToReadableStream(<ClientShell/>, ...) and feeds the Flight stream into the shell as it streams.
  3. The shell HTML hydrates on the client, reads the Flight stream from a <script> tag (or a fetch), and applies the resulting tree.

Fizz and Flight share the underlying ReactServerStreamConfig* infrastructure but otherwise are independent — Flight doesn't produce HTML, and Fizz doesn't know about client/server references.

Caching

cache(fn) (packages/react/src/ReactCacheImpl.js) on the server side memoizes a function across the same RSC request. On the client side it only works under the React Compiler. cacheSignal() returns an AbortSignal that fires when the surrounding cache lifetime ends — added in 19.2 and useful for canceling in-flight server fetches.

Where to read

  • packages/react-server — the writer.
  • packages/react-server-dom — bundler-specific clients.
  • packages/react-client/src/ReactFlightClient.js — the wire-format decoder.
  • fixtures/flight/ — small, runnable RSC apps for each bundler. Best place to read end-to-end code.
  • The CHANGELOG entries for 19.0 and 19.2 describe most of the user-visible RSC and Server-Action features.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Server Components – React wiki | Factory