RSC Overview
The @veloxts/web package enables React Server Components (RSC) with Vinxi and React 19, providing a unified full-stack architecture where server and client code coexist seamlessly.
What is RSC?
Section titled “What is RSC?”React Server Components allow components to render on the server by default, with the ability to mark specific components as client-side when needed:
// Server Component (default) - runs on server, no JS sent to clientasync function UserProfile({ userId }: { userId: string }) { const user = await db.user.findUniqueOrThrow({ where: { id: userId } }); return <div>{user.name}</div>;}
// Client Component - interactive, runs in browser'use client';function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(c => c + 1)}>{count}</button>;}Architecture
Section titled “Architecture”Browser Request ↓ Vinxi (Meta-framework) ↓┌─────────────────────────────────────┐│ React Server Components ││ ├── Server rendering (RSC) ││ ├── Server Actions → Procedures ││ └── Client hydration │└─────────────────────────────────────┘ ↓VeloxTS Procedures (Business Logic) ↓Database (Prisma)Quick Start
Section titled “Quick Start”# Full-stack RSCnpx create-velox-app my-app --rsccd my-apppnpm dev
# RSC with authenticationnpx create-velox-app my-app --rsc-authKey Features
Section titled “Key Features”| Feature | Description |
|---|---|
| Server Components | Components render on server by default—zero client JS |
| Server Actions | Type-safe mutations that call procedures directly |
| File-based Routing | Pages in app/pages/ map to URL routes |
| Nested Layouts | Compose layouts with shared UI and data loading |
| Streaming | Progressive page loading with Suspense boundaries |
| Type Safety | End-to-end types from database to UI |
Project Structure
Section titled “Project Structure”my-app/├── app/│ ├── pages/ # File-based routes│ │ ├── index.tsx # → /│ │ ├── about.tsx # → /about│ │ └── users/│ │ ├── index.tsx # → /users│ │ └── [id].tsx # → /users/:id│ ├── layouts/ # Layout components│ │ └── root.tsx # Root layout (wraps all pages)│ ├── actions/ # Server actions│ │ └── users.ts # User mutations│ └── components/ # Shared components├── api/│ ├── procedures/ # VeloxTS procedures│ └── index.ts # API entry point├── prisma/│ └── schema.prisma # Database schema└── app.config.ts # Vinxi configurationRSC vs SPA Templates
Section titled “RSC vs SPA Templates”| Aspect | RSC (--rsc, --rsc-auth) | SPA (--default, --auth) |
|---|---|---|
| Rendering | Server-first, streams HTML | Client-side rendering |
| Data Fetching | Server Components + Actions | API calls from browser |
| Bundle Size | Minimal client JS | Full React app in browser |
| SEO | Excellent (server-rendered) | Requires SSR/SSG setup |
| Interactivity | Opt-in with 'use client' | Everything is interactive |
| Best For | Content sites, dashboards | SPAs, mobile-first apps |
Server Actions Bridge
Section titled “Server Actions Bridge”Server Actions connect your React components to database operations with validation:
'use server';import { validated } from '@veloxts/web/server';import { z } from 'zod';
const CreateUserSchema = z.object({ name: z.string().min(1).max(100), email: z.string().email(),});
export const createUser = validated(CreateUserSchema, async (input, ctx) => { // input is typed: { name: string; email: string } const { db } = await import('@/api/database'); const user = await db.user.create({ data: input }); return { success: true, user };});
// app/pages/users/new.tsximport { createUser } from '@/app/actions/users';
export default function NewUserPage() { return ( <form action={createUser}> <input name="name" required /> <input name="email" type="email" required /> <button type="submit">Create User</button> </form> );}Next Steps
Section titled “Next Steps”- Server Actions - Type-safe mutations with validation
- File Routing - Route patterns and dynamic segments
- Layouts - Nested layout composition
- tRPC Bridge - Call procedures from server components