Package Exports
- vite-plugin-react-server
- vite-plugin-react-server/client
- vite-plugin-react-server/components
- vite-plugin-react-server/config
- vite-plugin-react-server/config/createHandlerOptions
- vite-plugin-react-server/css-loader
- vite-plugin-react-server/dev-server
- vite-plugin-react-server/dev-server/cleanupServerAction
- vite-plugin-react-server/dev-server/configureReactServer
- vite-plugin-react-server/dev-server/configureRequestHandler
- vite-plugin-react-server/dev-server/handleServerAction
- vite-plugin-react-server/dev-server/restartWorker
- vite-plugin-react-server/directives
- vite-plugin-react-server/env
- vite-plugin-react-server/env-loader
- vite-plugin-react-server/env/plugin
- vite-plugin-react-server/error
- vite-plugin-react-server/file-preserver
- vite-plugin-react-server/helpers
- vite-plugin-react-server/helpers/handleServerAction
- vite-plugin-react-server/helpers/resolveStreamElements
- vite-plugin-react-server/html-worker
- vite-plugin-react-server/loader
- vite-plugin-react-server/metrics
- vite-plugin-react-server/orchestrator
- vite-plugin-react-server/orchestrator/createPluginOrchestrator
- vite-plugin-react-server/package.json
- vite-plugin-react-server/plugin
- vite-plugin-react-server/react-client
- vite-plugin-react-server/react-client/plugin
- vite-plugin-react-server/react-server
- vite-plugin-react-server/react-server/plugin
- vite-plugin-react-server/react-static
- vite-plugin-react-server/react-static/createBuildLoader
- vite-plugin-react-server/react-static/inlineFlightPayload
- vite-plugin-react-server/react-static/plugin
- vite-plugin-react-server/react-static/renderPage
- vite-plugin-react-server/react-static/rscToHtmlStream
- vite-plugin-react-server/react-static/temporaryReferences
- vite-plugin-react-server/references
- vite-plugin-react-server/register
- vite-plugin-react-server/rsc-worker
- vite-plugin-react-server/server
- vite-plugin-react-server/static
- vite-plugin-react-server/storybook
- vite-plugin-react-server/stream
- vite-plugin-react-server/stream/client
- vite-plugin-react-server/stream/createFromNodeStream
- vite-plugin-react-server/stream/createHtmlStream
- vite-plugin-react-server/stream/createRenderToPipeableStreamHandler
- vite-plugin-react-server/stream/createRscStream
- vite-plugin-react-server/stream/handleRscStream
- vite-plugin-react-server/stream/server
- vite-plugin-react-server/transformer
- vite-plugin-react-server/transformer/plugin
- vite-plugin-react-server/types
- vite-plugin-react-server/utils
- vite-plugin-react-server/utils/rsc-client
- vite-plugin-react-server/vendor
- vite-plugin-react-server/vendor.client
- vite-plugin-react-server/vendor.server
- vite-plugin-react-server/vendor.static
- vite-plugin-react-server/virtual
- vite-plugin-react-server/worker
Readme
vite-plugin-react-server
React Server Components as a Vite plugin. One vite build --app prerenders your
pages to static HTML + RSC payloads and emits your components as portable ESM
that runs under any HTTP server: static hosting, Express/Hono, or anything in
between.
📖 Documentation site → — the full docs, and itself a vprs app (the site dogfoods the plugin).
vprs is the low-level layer rather than a framework: it handles the RSC
transform, runs the worker threads, and emits portable ESM — and leaves routing
and app structure to you. Use it directly, or as the engine under your own
conventions. Its closest peer is the official
@vitejs/plugin-rsc;
vprs differs by being a small dev/build setup whose output is portable ESM you
host yourself. (The RSC transport underneath is an implementation detail —
supplied and version-locked by react-server-loader.) For a batteries-included
framework instead, see Waku or Vike. Full breakdown:
How vprs compares.
It runs in both Node module conditions by design: the dev server and the build
work with or without --conditions react-server, and a worker thread mirrors
whichever half your main thread isn't on (server components need a react-server
context, client hydration a react-client one). Running the main thread under
react-server is an optional optimization — a bit faster, better stack traces —
never a requirement.
Install
npm install -D vite-plugin-react-server react react-domvprs runs on stable React 19.2+ out of the box — and on experimental React
too. Everything locked to a React version (the react-server-dom-esm transport
that ships on both the server and your browser bundle, the directive engine, the
Node loader) lives in the
react-server-loader
dependency, whose versions track React the way @types/react does. You don't
build or manage a transport — you pick a React track and install the matching
react-server-loader. The command above is all you need for stable.
To run the experimental train instead, install the three together; the
react-server-loader range collapses them to one copy, so no overrides are
needed:
npm install react@experimental react-dom@experimental react-server-loader@experimentalExperimental buys the newest RSC features ahead of stable — for instance it
already fixes the cosmetic as="stylesheet" CSS-preload warning that stable
React 19.2.x logs. See React Compatibility;
upgrading from 1.x, see the
migration notes.
Minimal Example
// vite.config.ts
import { defineConfig } from "vite";
import { vitePluginReactServer } from "vite-plugin-react-server";
export default defineConfig({
plugins: vitePluginReactServer({
moduleBase: "src",
Page: "src/page.tsx",
build: { pages: ["/"] },
}),
});// src/page.tsx
export const Page = ({ url }: { url: string }) => <div>Hello from {url}</div>;# Dev server
npx vite
# Build (static site + server/client ESM)
npx vite build --app
# Same build, react-server main thread — optional: a bit faster, better stack traces
NODE_OPTIONS='--conditions react-server' vite build --appBuild Output
dist/
├── static/ # Deployable to any static host
│ ├── index.html # Pre-rendered HTML
│ └── index.rsc # RSC payload for client navigation
├── client/ # Client-side ESM modules (for SSR)
└── server/ # Server-side ESM modules (with server actions)dist/static/ is a complete static site. dist/client/ and dist/server/ are ESM modules you can import in your own Express/Hono/Node server.
Client components
vprs recognises a file as a client module when either of these is true:
- the filename matches
(^|[\/.])client\.[cm]?[jt]sx?$— i.e.Button.client.tsx,bar.client.mjs, or the standalone basenamesrc/client.tsx/client.tsx, or - the file starts with a top-of-file
"use client"directive (leading whitespace, line/block comments, and an optional"use strict"prologue are tolerated above it).
Either is sufficient. Substrings like clientUtils.tsx, clientId.ts, or clients.tsx are not treated as client modules, and a "use client" directive placed after real code does not count.
// src/components/Counter.tsx ← no `.client.` suffix needed
"use client";
import { useState } from "react";
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}See Getting Started.
Third-party client-component packages
Component libraries like Chakra UI, MUI, Mantine, react-aria, and framer-motion are client-only — their components rely on React context/state and must run inside a client boundary, the same constraint they carry under Next.js's App Router. Use them within a "use client" component (commonly a small provider wrapper); they can't be imported directly into a server component. This isn't a vprs limitation — e.g. Chakra's own Next.js App Router guide requires wrapping ChakraProvider in a 'use client' component.
vprs auto-detects these so they're treated correctly at build start: any package with react in its peerDependencies is classified as a client package (using vitefu.crawlFrameworkPkgs). Two escape hatches if needed:
vitePluginReactServer({
// Force a package into the list (e.g. one that doesn't peerDep react)
clientPackages: ["@my/internal-ui"],
// Skip a detected one (e.g. devDeps Storybook bringing along @storybook/react)
excludeClientPackages: ["@storybook/react", "@storybook/react-vite"],
});Storybook
vprs ships a Storybook preset — add one line and your RSC app's components build and render in Storybook:
// .storybook/main.ts
export default {
framework: { name: "@storybook/react-vite", options: {} },
addons: ["vite-plugin-react-server/storybook"],
};It strips the vprs plugin from Storybook's builder, resolves the
react-server-dom-esm transport (from react-server-loader), and silences
"use client"/"use server" directive noise. See
Storybook for details.
Documentation
Everything below is also published as a browsable site at nicobrinkkemper.github.io/vite-plugin-react-server, which is itself built with vprs.
| Doc | What it covers |
|---|---|
| How vprs compares | vprs vs @vitejs/plugin-rsc, Waku, Vike — and what vprs does not do |
| Getting Started | Install → first page → dev server → build → deploy |
| Storybook | One-line Storybook support for vprs apps |
| Build Output | What the build produces, how to use the ESM modules |
| Configuration | All plugin options |
| CSS Handling | Inline/linked CSS, CSS modules, the Css component |
| Server Actions | "use server" directives, form actions, hosting |
| Examples | Static site, dynamic server, server actions, custom routing |
| Troubleshooting | Common errors and fixes |
| API Reference | Exported functions, types, and components |
Internals (contributors)
| Doc | What it covers |
|---|---|
| Architecture | Condition system, module structure, plugin composition |
| Transformer | How "use client" / "use server" directives are processed |
| Workers | RSC and HTML worker threads |
Maintenance
| Doc | What it covers |
|---|---|
| Releasing | Version bumps, publishing, demo updates |
| React Compatibility | Vendored ESM transport, type system |
Requirements
- Node.js 22.0.0+ (the build uses
node:fs/promises#glob, which landed in 22) - React 19.2+, stable (
react/react-domat^19.2.7) or experimental. The RSC server APIs vprs uses (prerenderToNodeStream, thereact-servertransport exports) ship in stable React; the matchingreact-server-dom-esmtransport comes from thereact-server-loaderdependency, which tracks your React track. See React Compatibility. - Vite 6+
TypeScript
{
"compilerOptions": {
"types": ["vite/client", "vite-plugin-react-server/virtual"]
}
}License
MIT