Skip to main content

Introduction

The one-minute idea

React Server Components split one program across two computers. Between the server half and the browser half is a one-way door: only serializable data crosses it. Server components run, produce data, and disappear. Client components are shipped as references and run in the browser.

PHP already lives on the server side of that door — a PHP script runs, produces HTML, and disappears. Nothing new there. What's new is PHPX: it compiles JSX-like markup into serializable tuples:

['$', 'tag', props, children]

That's the same shape as React's element / Flight format. Because the tuple is the data structure React already uses to describe an element tree, most of the RSC model turns out to be portable to PHP — for free, because PHP was already doing the server half.

phpx-server is that port. It exists to answer one question: how much of the RSC model is actually portable to PHP? The answer is: most of the server half.

What's ported

RSC capabilityPorted hereHow
Server componentsPHPX components run on the server and render to HTML. This is PHP.
The boundary ("the door")Only JSON-serializable props cross to the client. Closures stay on the server.
Suspense streamingA Suspense boundary + PHP Fibers: the shell streams first, boundaries resolve out of order.
Nested / parallel SuspenseBoundaries nest arbitrarily; independent ones resolve in parallel.
Error boundariesErrorBoundary catches a subtree's error and streams a fallback.
Client componentsClient('Name', $props) emits a serializable reference; a React island mounts into it.
Server actionsA named-callable registry, invoked by a plain <form> (no JS) or by fetch (JSON); redirect() supported.
Flight navigationThe server returns the serialized tuple tree as JSON; the client rebuilds the view, no reload.
Streaming FlightThe Flight payload as NDJSON — shell first, boundaries out of order.
cache()Per-request memoization / dedup of data loading.
Head & metadataComponents/routes contribute <title>/<meta>/<link>, hoisted into <head>.
Router UXPrefetch-on-hover and a pending indicator during navigation.

The honest limit

Browser interactivity needs JavaScript. That's physics, not a PHP limitation, and phpx-server doesn't pretend otherwise.

  • Server components — the parts that just render data to markup — port for free. They never needed JavaScript in React either; PHPX just gives PHP the same declarative, composable syntax React uses.
  • Interactive leaves — a button that needs onClick, an input with local state — become React islands: small client components hydrated into specific spots in server-rendered markup.

This is progressive enhancement, not isomorphism. There's no single component tree that runs identically on both PHP and JavaScript. There's a PHP tree that renders the page, and a React tree that mounts on top of specific nodes once the browser has JS. The todo example works completely without JavaScript; React only makes it feel instant.

Who this is for

The rest of these docs assume you're coming from one of two directions:

  • React developers curious how much of the mental model — Suspense, server/client boundaries, server actions — survives outside Node.
  • PHP developers curious what RSC actually is, once you strip away the bundler/router/framework machinery and look at the underlying idea.

Each concept page frames itself from both sides.