@lazarv
react-server
Run React anywhere
Execute React components across server, client, workers, and edge environments using a single runtime — with React Server Components, streaming, and deployment built in.
The Idea
React as a Runtime
React runs outside the browser. Components are executable units — they run on the server, in workers, and at the edge. The runtime decides where and how each component executes.
There is no framework boundary. You write React, and the same model works everywhere. A component can fetch data on the server, stream HTML to the client, or process images in a worker thread — all with the same syntax.
A single directive — "use client", "use worker", or "use live" — is all it takes to change where a component runs. No build-step magic, no separate APIs to learn. The runtime handles serialization, streaming, and hydration automatically.
This means your application is one unified React tree, not a patchwork of server code, client code, and glue in between. Scale from a single file to a distributed system without switching paradigms.
React components are no longer just UI — they are executable units of an application runtime.
Server component — runs on the server. Access databases and APIs directly, no client bundle cost.
export default async function Page() {
const data = await db.query("SELECT ...");
return <Feed items={data} />;
}
Client component — hydrates in the browser. Same React you already know.
"use client";
export default function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>{n}</button>;
}
Worker — runs in a background thread. Offload heavy work without blocking the server or the UI.
"use worker";
export async function resize(buf) {
return sharp(buf).resize(800).toBuffer();
}
Live component — streams updates over WebSocket. Each yield pushes a new React tree to the client.
"use live";
export default async function* Price({ symbol }) {
while (true) {
yield <span>{await getPrice(symbol)}</span>;
await new Promise((r) => setTimeout(r, 1000));
}
}
@lazarv/react-server is a runtime for executing React components across server, client, workers, and edge environments.
Create a single file — that's your entire app. No config, no boilerplate. Run it with npx @lazarv/react-server ./App.jsx and you're live.
export default function App() {
return <h1>Hello World!</h1>;
}
When you're ready to scale, add a page to app/page.jsx and drop the entrypoint. The file-system router takes over automatically.
export default async function Home() {
const posts = await db.posts.findMany();
return (
<main>
<h1>Blog</h1>
{posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</main>
);
}
Philosophy
Why @lazarv/react-server?
Most React frameworks require significant setup before you write your first component. @lazarv/react-server takes a different approach — it's as simple as running a script with node, but for React.
Start with a single file and scale to a full-featured application with file-system routing, caching, static generation, and multi-runtime deployment as your needs grow.
Built on Vite for instant HMR. Ships with its own React, so your project stays lean. Supports Node.js, Bun, and Deno. Deploys to Vercel, Netlify, Cloudflare, and more with built-in adapters.
Start in Seconds
One dependency. One file. One command.
Quick Start
Install & Run
Add a single dependency, create a .jsx file that exports a React component, and start the dev server. That's it — full SSR with hot module replacement, no boilerplate.
You don't even need to install React. It's bundled with the framework and always kept up to date.
Add the framework to your project with a single dependency — React is included, no separate install needed.
pnpm add @lazarv/react-server
Write a default-exported React component. This file is your entire application entry point.
export default function App() {
return <h1>Hello World!</h1>;
}
Start the development server with instant hot module replacement powered by Vite.
pnpm react-server ./App.jsx
Skip installation entirely — run any React file directly with npx. Perfect for quick experiments and prototyping.
npx @lazarv/react-server ./App.jsx
Bootstrap a runtime application with file-system routing, layouts, and production-ready config using the create package.
npx @lazarv/create-react-server
Start the development server with instant HMR powered by Vite.
react-server
Create an optimized production build, then serve it with built-in compression and cluster mode.
react-server build react-server start
Alternatives
More Ways to Start
Skip installation entirely with npx to run any React file on the fly — ideal for prototyping and quick demos. Or use the create package to scaffold a full project with file-system routing, layouts, and production config already wired up.
The scaffolded project gives you a complete development workflow: a dev server with instant HMR, an optimized production build step, and a production server with compression, caching, and cluster mode — all through the react-server CLI with zero additional configuration.
Core Execution Model
Server components, client interactivity, server functions, and streaming — the rendering foundation.
Default Rendering
React Server Components
Server components execute on the server, support async/await, and their code never reaches the client. Access databases, file systems, and internal APIs directly — no separate backend needed.
There is no hydration cost for server-only components. Faster page loads, smaller bundles, simpler architecture.
export default async function Dashboard() {
const stats = await fetch(
"https://api.example.com/stats",
{ headers: { Authorization: `Bearer ${API_KEY}` } }
).then((r) => r.json());
return (
<section>
<h1>Dashboard</h1>
<p>Total users: {stats.users}</p>
<p>Revenue: ${stats.revenue}</p>
</section>
);
}
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Current count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
Interactivity
Client Components
Add "use client" to enable interactivity. Components are server-rendered first for fast initial paint, then hydrated on the client with full hook and event handler support.
You only pay the hydration cost where you actually need interactivity. Everything else stays server-only.
Data Mutations
Server Functions
"use server" turns any async function into a server-side RPC endpoint. Use them as form actions with progressive enhancement — forms work even without JavaScript.
No API routes to define, no fetch wrappers. The framework handles serialization, error boundaries, and revalidation.
async function createPost(formData) {
"use server";
const title = formData.get("title");
const body = formData.get("body");
await db.posts.create({ title, body });
revalidate("/posts");
}
export default function NewPost() {
return (
<form action={createPost}>
<input name="title" placeholder="Title" />
<textarea name="body" placeholder="Content" />
<button type="submit">Publish</button>
</form>
);
}
import { Suspense } from "react";
async function SlowData() {
const data = await fetchFromSlowAPI();
return <div>{data.result}</div>;
}
export default function Page() {
return (
<main>
<h1>Instant header</h1>
<p>This content appears immediately.</p>
<Suspense fallback={<p>Loading data...</p>}>
<SlowData />
</Suspense>
</main>
);
}
Performance
Streaming SSR
HTML streams to the client as soon as it's available. Combined with <Suspense>, parts of the page render progressively — users see content immediately while slower sections load in the background.
Fast time-to-first-byte from streaming. Complete interactive experience once hydration finishes. No configuration required.
Distributed React
Push components beyond a single process — live streaming, worker threads, and micro-frontends.
Real-Time
Live Components
Server-to-client streaming with async generators over WebSocket. Each component instance gets its own persistent server-side execution context.
Add "use live" and export an async generator. Each yield sends a new React tree to the client. Ideal for dashboards, feeds, and monitoring.
"use live";
export default async function* StockPrice({ symbol }) {
while (true) {
const price = await getPrice(symbol);
const trend = await getTrend(symbol);
yield (
<div>
<span className="text-2xl">${price}</span>
<span className={trend > 0 ? "green" : "red"}>
{trend > 0 ? "▲" : "▼"} {Math.abs(trend)}%
</span>
</div>
);
await new Promise((r) => setTimeout(r, 1000));
}
}
"use worker";
export async function processImage(buffer, options) {
// Runs in a Worker Thread — won't block
// the main server or the UI thread
const result = await sharp(buffer)
.resize(options.width, options.height)
.webp({ quality: options.quality })
.toBuffer();
return result;
}
Concurrency
Workers
Offload heavy computation to background threads with "use worker". Worker Threads on the server, Web Workers in the browser.
Arguments and return values serialize via the RSC Flight protocol — return React elements directly. Full HMR support.
Composition
Micro-Frontends
Compose independently deployed RSC applications. Each remote app streams into the host page. isolate enables shadow DOM encapsulation so styles never leak.
Share dependencies via import maps. Render with defer for non-blocking loading. Export as static builds for edge distribution.
import { RemoteComponent }
from "@lazarv/react-server/remote";
export default function App() {
return (
<main>
<h1>Host Application</h1>
<RemoteComponent
src="https://team-a.example.com/header"
/>
<RemoteComponent
src="https://team-b.example.com/widget"
isolate
defer
/>
</main>
);
}
Platform Features
Application capabilities built on top of the runtime — routing, navigation, caching, and content composition.
Routing
File-System Router
Omit the entrypoint and the framework routes based on your file structure. Pages, layouts, parallel outlets, API routes, middlewares, error boundaries, loading states — all convention-driven.
Dynamic segments, catch-all routes, route groups, and typed route generation are built in.
app/
├── layout.jsx # Root layout
├── page.jsx # /
├── about.jsx # /about
├── posts/
│ ├── page.jsx # /posts
│ ├── [id].jsx # /posts/:id
│ └── [...slug].jsx # /posts/*
├── (auth)/
│ └── login.jsx # /login (grouped)
├── @sidebar/
│ └── page.jsx # Parallel outlet
├── loading.jsx # Suspense fallback
├── error.jsx # Error boundary
├── (i18n).middleware.mjs # Middleware
└── GET.api.server.mjs # GET /api endpoint
import { Link } from "@lazarv/react-server/navigation";
export default function Nav() {
return (
<nav>
<Link to="/" prefetch>Home</Link>
<Link to="/about" prefetch>About</Link>
<Link to="/posts" prefetch="viewport">
Posts
</Link>
</nav>
);
}
Navigation
Client-Side Navigation
SPA-like transitions with Link, Form, Refresh, and ReactServerComponent. Prefetch on hover or viewport entry, roll back on error, scope updates to specific outlets.
Programmatic navigation via useClient() integrates with the streaming architecture — no blank-screen transitions.
Caching
Caching & Revalidation
Multi-layered caching at every level — response, data, and component. Built on Unstorage with pluggable drivers.
Invalidate on demand with revalidate() and invalidate(). Use the "use cache" directive for declarative TTL and tag-based invalidation.
import { useResponseCache, useCache } from "@lazarv/react-server";
Cache the full rendered response for 30 seconds — subsequent requests skip rendering entirely.
useResponseCache(30000);
Cache individual data fetches with compound keys. Each entry has its own TTL and can be invalidated independently.
const post = await useCache(
["posts", id],
() => fetchPost(id),
60000
);
Or use the "use cache" directive at the top of a file for declarative TTL and tag-based invalidation.
"use cache; ttl=60; tags=posts"
The page shell and static components are pre-rendered at build time and served instantly from the edge.
export default function ProductPage({ params }) {
return (
<main>
<StaticHeader />
<ProductInfo id={params.id} />
<DynamicReviews id={params.id} />
</main>
);
}
Dynamic components marked with "use dynamic" stream in at request time while the static shell is already visible.
"use dynamic";
export default async function DynamicReviews({ id }) {
const reviews = await fetchReviews(id);
return (
<section>
{reviews.map((r) => <Review key={r.id} {...r} />)}
</section>
);
}
Hybrid Rendering
Partial Pre-Rendering
Mix static and dynamic content at the component level. Static shells pre-render at build time; dynamic parts stream in at request time.
Mark components with "use dynamic" or "use static". Static portions serve instantly from the edge while dynamic data loads.
Content
Markdown & MDX
Use .md and .mdx files directly as pages with full remark/rehype plugin support and custom component overrides.
Embed React components inside Markdown. Define custom components once and apply them globally for full rendering control.
Define custom component overrides once in mdx-components.jsx — they apply globally to all your MDX content.
export function useMDXComponents() {
return {
h1: (props) => (
<h1 className="text-4xl font-bold" {...props} />
),
code: ({ children, className }) => (
<SyntaxHighlighter language={className}>
{children}
</SyntaxHighlighter>
),
a: (props) => (
<Link className="text-blue-600" {...props} />
),
};
}
import { createServer, createTool }
from "@lazarv/react-server/mcp";
import { z } from "zod";
const search = createTool(
"search",
"Search the knowledge base",
{
query: z.string(),
limit: z.number().default(10),
},
async ({ query, limit }) => {
const results = await db.search(query, limit);
return results.map((r) => r.title).join("\n");
}
);
export default createServer({ tools: [search] });
AI Integration
MCP Server
Build Model Context Protocol servers with tools, resources, and prompts as streaming HTTP endpoints.
Define tools with Zod schemas. AI agents discover and invoke them through a standardized protocol. Each tool becomes an HTTP endpoint compatible with any MCP client.
Deploy Anywhere
One command to build for production. Built-in adapters for every major platform — or bring your own.
Adapters
Platform Adapters
Deploy to Vercel, Netlify, or Cloudflare with a single config option. Each adapter handles platform-specific output — edge functions, serverless functions, Workers — automatically.
Need something custom? Build your own adapter with createAdapter from the adapter core package. The adapter API gives you full control over the build output.
A single command builds your app and generates platform-specific deployment output.
react-server build --deploy
Set the adapter in your config file — the build outputs edge functions, serverless functions, or Workers automatically.
{ "adapter": "vercel" }
Or pass the adapter directly as a CLI argument — no config file needed.
react-server build --adapter vercel --deploy
Use middleware mode to embed the framework into any existing Express, NestJS, or connect-compatible server.
import { reactServer } from
"@lazarv/react-server/node";
const { middlewares } = await reactServer();
app.use(middlewares);
Scale horizontally across all available CPU cores with cluster mode for maximum throughput.
REACT_SERVER_CLUSTER=8 react-server start
Or configure the cluster size in your config file for consistent production deployments.
{ "cluster": 8 }
Runtime
Multi-Runtime & Production
Run on Node.js ≥ 20.10, Bun ≥ 1.2.9, or Deno ≥ 2.0 — the framework auto-detects your runtime. Embed into any existing server with middleware mode.
Scale across all CPU cores with cluster mode. Static export generates fully static sites with dynamic route params, compression, and cache headers. HTTPS, source maps, and gzip/brotli compression are built in.
Ready to Build?
Join a growing community of developers building modern React applications with server-side rendering, streaming, and edge deployment. Open source, MIT licensed, and actively maintained.