Core Concepts
Understanding these five ideas covers 90% of how RebaseJS behaves.
1. Rendering Modes
RebaseJS has three primary rendering modes. Each is a deliberate choice per route — never a global setting.
| Mode | How it works | When to use |
|---|---|---|
| CSR (default) | Page renders in the browser. Server sends a minimal HTML shell. | Dashboards, auth-gated apps, highly interactive local-first UIs. |
| SSR | Server renders the full HTML on every request. Client hydrates. | Public pages, SEO-critical content, content that changes per user. |
| PPR (Partial Prerendering) | Static HTML shell pre-rendered at build time; dynamic sections stream in. | Marketing pages with personalised widgets, landing pages. |
Choosing a mode
Is this page public / needs SEO?
Yes → SSR (export const ssr = true)
No → CSR (default, no config needed)
Does it have a static outer shell + dynamic inner content?
Yes → PPR (export const ppr = true, export const ssr = true)2. Route Kinds
The file name inside app/ determines what a file does. RebaseJS recognises five primary route kinds:
| File | Kind | Purpose |
|---|---|---|
page.tsx | page | Renders a UI at the current path |
layout.tsx | layout | Wraps all child pages in a shared shell |
loading.tsx | loading | Suspense fallback shown while data loads |
error.tsx | error | Error boundary for the current subtree |
route.ts | api | HTTP endpoint (GET, POST, PUT, PATCH, DELETE) |
The Rust scanner builds a route manifest at build time. Every route kind maps to a stable path pattern. The manifest is written to .rebasejs/dist/route-manifest.json and is the single source of truth for the whole system.
3. Server / Client Boundary
The boundary is enforced by file naming, not directives.
app/
page.tsx ← runs in the browser (CSR default)
page.tsx + ssr=true ← runs on the server AND the browser
route.ts ← runs on the server only (API handler)
lib/
db.server.ts ← runs on the server only
utils.ts ← shared (no DB imports allowed here)Files ending in .server.ts are never bundled for the browser. The Rust compiler enforces this at build time — if a client module imports a .server.ts file directly, the build fails with a clear error.
4. Request Lifecycle
Browser request
│
▼
Middleware (middleware.ts)
│ auth checks, redirects, locale detection
▼
Route handler
├── page.tsx (CSR) → serve HTML shell, browser fetches JS, renders
├── page.tsx (SSR) → render React to HTML on server, stream to browser
└── route.ts → run GET/POST/… handler, return Response
│
▼
Server functions (*.server.ts)
│ called by useServerData / useMutation / live components
└── database, external APIs, secrets — never reach the browser5. Build Pipeline
Running rebase build executes these steps in order:
1. Vite + Rolldown (Rust)
└── Client bundle → .rebasejs/dist/client/
2. Rust route scanner
└── Walks app/, classifies files, writes route-manifest.json
3. Route type generator
└── Writes .rebasejs/routes.d.ts (RebaseRoutes union + typed navigate)
4. TypeScript type checker
└── tsc --noEmit (routes.d.ts is available here)
5. Rust route reference checker
└── Validates <RouteLink to>, <Link href>, navigate() against manifest
6. esbuild SSR bundle
└── Server pages → .rebasejs/dist/server/
7. PPR shells (if any)
└── Pre-renders static HTML → .rebasejs/ppr-cache/
8. Build ID
└── git SHA (or FNV-1a hash fallback) → .rebasejs/dist/BUILD_IDThe key ordering constraint: route types are generated before tsc runs, so RebaseRoutes is always resolvable on the first build.
6. RebaseRoutes — Type-Safe Navigation
Every page route in app/ is reflected in a generated TypeScript union:
// .rebasejs/routes.d.ts (auto-generated — do not edit)
export type RebaseRoutes = "/" | "/about" | `/users/${string}` | `/posts/${string}`;This type is used by navigate(), <RouteLink to>, and <Link href> so the compiler catches dead links at build time.
import { navigate } from "rebasejs/router";
// ✅ known route
navigate("/about");
// ✗ build error: "/abuot" is not assignable to RebaseRoutes
navigate("/abuot");To enable these checks, add .rebasejs/routes.d.ts to your tsconfig.json:
{
"include": ["app", ".rebasejs/routes.d.ts"]
}