A React-based server framework where you define routes using JSX components, combining the power of React with Fastify's performance.
- π― JSX as Configuration - Define routes declaratively with React components
- π‘οΈ Guards & Middleware - Built-in support for authentication and request processing
- π TypeScript-First - Full type safety with generic type parameters
- β‘ Fastify Powered - Blazing fast HTTP server under the hood
- π¨ Nested Routes - Organize routes with
<Controller>components - π Page Rendering - SSR and SPA support with automatic bundling
- βοΈ Full React SPA - Build interactive pages with hooks, state, and effects
- π Hot Reload - Development mode with automatic cache invalidation
- π "use spa" Directive - Auto-discovery of SPA components at startup
- π Bun & Node Compatible - Works with both runtimes seamlessly
# Using Bun (recommended)
bun add react-server-app react react-dom
# Using npm
npm install react-server-app react react-dom
# For SPA mode, also install:
bun add vite @vitejs/plugin-react
# or
npm install vite @vitejs/plugin-reactimport React from "react";
import { App, Route, createServer } from "react-server-app";
const server = (
<App port={3000}>
<Route path="/hello" method="GET" onRequest={() => ({ message: "Hello World!" })} />
</App>
);
createServer(server);Run with:
bun run server.tsx
# or
tsx server.tsxVisit http://localhost:3000/hello
π See Full Quick Start Guide
- Quick Start Guide - Get started in 5 minutes
- API Components - All available components
- Guards & Middleware - Authentication and request processing
- SPA Pages - Build interactive pages
- Configuration - Framework configuration options
- "use spa" Directive - Auto-discovery of SPA components
<Route
path="/users/:id"
method="GET"
onRequest={({ params }) => ({
userId: params.id,
name: "John Doe",
})}
/><Controller path="/api">
<Controller path="/users">
<Route path="/" method="GET" onRequest={() => getAllUsers()} />
<Route path="/:id" method="GET" onRequest={({ params }) => getUser(params.id)} />
<Route path="/" method="POST" onRequest={({ body }) => createUser(body)} />
</Controller>
</Controller><Guard use={authGuard}>
<Route path="/dashboard" method="GET" onRequest={getDashboard} />
<Route path="/profile" method="GET" onRequest={getProfile} />
</Guard>// dashboard.tsx
"use spa";
import { useState } from "react";
export default function Dashboard() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
// server.tsx
<Route
path="/dashboard"
method="GET"
onRequest={() => (
<Page spa={true} title="Dashboard">
<Dashboard />
</Page>
)}
/>;<App>- Root component that starts the server<Controller>- Groups routes under a common path<Route>- Defines HTTP endpoints<Guard>- Protects routes with authorization logic<Middleware>- Processes requests before handlers<Page>- Renders HTML pages (SSR or SPA)<Response>- Declarative response formatting
Full type safety with generic type parameters:
interface UserParams {
id: string;
}
interface User {
id: string;
name: string;
email: string;
}
<Route<UserParams, never, never, User>
path="/users/:id"
method="GET"
onRequest={({ params }) => {
// params.id is typed as string
return {
id: params.id,
name: "John Doe",
email: "john@example.com",
};
}}
/>;Configure the framework to your needs:
import { configure } from "react-server-app";
configure({
bundler: "vite", // or 'bun'
minify: true, // Minify bundles
cache: true, // Enable caching
spaComponentDirs: [
// Directories to scan for "use spa"
"pages",
"components",
],
spaComponentExclude: [
// Directories to exclude
"node_modules",
"dist",
],
});Development mode automatically watches your files and clears the cache when changes are detected. No server restart needed!
// Just save your file and changes are reflected immediatelyAuto-discover SPA components at startup:
// pages/Dashboard.tsx
"use spa";
export default function Dashboard() {
return <div>Auto-discovered!</div>;
}No registration needed - the framework finds it automatically.
π Read the full guide
Supports multiple bundlers with a clean plugin architecture:
- Bun Bundler - Native Bun bundling (very fast)
- Vite Bundler - Industry-standard bundler (Node.js compatible)
Add your own bundler by implementing the Bundler interface!
Check out the demo application for a complete working example with:
- Authentication guards
- CORS middleware
- API routes
- Interactive SPA pages
- TypeScript types
- "use spa" directive usage
Contributions are welcome! Please feel free to submit a Pull Request.
MIT
Wesley Caldas
- npm: react-server-app
- Documentation: Quick Start Guide
Built with β€οΈ using React, Fastify, and TypeScript