Robust Universal Validation & Yielding eXperience Application
A React framework whose compiler, dev server, and production host are one Rust binary.
File-system routes, server rendering, actions, eleven deploy targets — or the whole site inside your own Rust service.
| Guide | Description |
|---|---|
| Documentation Home | Full manual — English and Thai editions |
| Introduction | What Ruvyxa is and when to use it |
| Create Your First App | Scaffold, run, and build a first vertical slice |
| Project Structure | app/, public/, config, and generated output |
| Routing & Rendering | File-system routes, layouts, SSR/SSG/ISR/CSR/PPR |
| Data, Actions & API | Loaders, cache(), server actions, API routes |
| UI, Navigation & Assets | Components, metadata, images, fonts |
| Configuration | ruvyxa.config.ts and environment variables |
| Request pipeline | Headers, redirects, rewrites, proxy, route files |
| Integrations | @ruvyxa/auth, database, realtime |
| CLI | Scripts, scaffolding, and the build loop |
| Architecture | Graph, bundler, dev server, diagnostics |
| Development & Testing | Develop, test, and package the framework |
| Security | Boundary enforcement and env safety |
| Observability & Performance | Logging, timing, caching, budgets |
| Deploy, Run & Operate | Adapters and platform-specific configuration |
| Troubleshooting | Diagnostic catalog and upgrade notes |
| Public API Reference | Complete @ruvyxa/react + @ruvyxa/core API |
| Documentation Scope | What the manual covers and its sources |
| Release Readiness | Pre-release verification playbook |
| Platform Adapter Guide | Writing a custom deployment adapter |
| Practical Recipes | Task-oriented end-to-end examples |
A full Thai edition lives beside the English one under docs/th/. Repository-level
documents: ARCHITECTURE.md, CHANGELOG.md,
CONTRIBUTING.md, SECURITY.md,
CODE_OF_CONDUCT.md, and AGENTS.md for agent/contributor rules.
The conventions are the familiar ones — an app/ directory, page.tsx, layout.tsx, route.ts,
server actions, and SSR, SSG, ISR, CSR, or PPR chosen per route — because the conventions are not
the point. What is different is what runs them, and what that makes possible.
- The toolchain is one prebuilt binary. The TypeScript/JSX compiler, resolver, linker, minifier,
source maps, route graph, dev server, and production host are Rust, shipped as a native CLI that
npm installresolves for your platform. There is no separate bundler to install or configure and no plugin chain. The benchmarks below are a consequence of that, not the reason for it. - Your Rust backend can serve the site.
ruvyxa adds axumwrites aCargo.tomland asrc/main.rsbuilt on theruvyxa-axumcrate, which serves the static build from anaxum::Routerbeside your own routes: one executable, no JavaScript runtime on the host, no second process, no reverse proxy joining the two, and the same security headers on your API as on the pages. It covers the static target — SSG and CSR routes; a route that renders on the server stays withruvyxa startor a deploy adapter. See one binary for the site and the API. - The deploy target is not hidden. Eleven adapters emit each platform's native artifact, and the deployed build is held to the same conformance fixtures as the native host — headers, cache policy, endpoints, stored documents — so a project moves between Node, Bun, Deno, a static host, an edge worker, and a serverless function without a preferred vendor and without a behaviour that exists on one host only.
- Two hosts, one contract.
ruvyxa devandruvyxa startrun on the Rust host; every deployed build runs oncreateHandler. A rule that applied on one and not the other is the shape of defect this project has fixed most often, so those rules are now fixtures both hosts replay in their own tests — not a comment saying the two agree.
If you write React and deploy to a JavaScript platform, the first and third are what you get. If you write Rust and want a React front end without a second deployment, the second is the reason this project is in your world at all. The rest of this section is the feature catalog.
- Ruvyxa Bundler — TypeScript/JSX/Markdown/MDX compilation, module resolution, tree-shaking, Oxc-backed minification, and source map generation in one self-contained binary.
- Radix-trie routing — O(path-depth) route resolution regardless of the number of registered routes. Duplicate and ambiguous routes are rejected at graph validation time.
- Persistent JavaScript worker pool — eliminates 100–500 ms per-request subprocess overhead for SSR. Shared across requests with layout nesting and route-level hydration bundles.
- LRU render cache — SSR pages and client bundles cached in-memory (capacity 1024 dev / 512
prod, TTL 5 min dev / 30 min prod), invalidated automatically on file change. Configurable via
RUVYXA_RENDER_CACHE_SIZE(0disables it; environment values are capped at 16,384). Backed byRwLockfor concurrent readers. - Parallel production bundling — route graphs are prepared once with bounded concurrency, then emitted once with shared-route modules in deterministic route order. Lightweight route plans and final/shared artifacts are content-validated, with each shared dependency fingerprinted once per build. Cold shared output reuses prepared modules; warm builds reuse the validated registry.
- Bounded build reuse — Node transforms, native dependency closures, and native Markdown/MDX output reuse content-keyed results. Prerendering loads its asset index once and shares immutable CSS across the bounded worker pool.
- Async I/O — file serving uses
tokio::fsto avoid blocking the async runtime under concurrent load. - Persistent incremental module graph — production builds persist content-verified dependency edges and reuse unchanged client resolution work on warm builds. The graph is namespaced by the evaluated config dependency hash; React-compiler transforms bypass edge reuse so their output stays correct. Compiled output remains content-addressed under the configured build cache.
- Typed artifact task graph — resolve, transform, analysis, chunk-plan, emit, source-map, and
manifest records share explicit dependency edges and generation-scoped completion. Records are
persisted atomically beside the build cache; corrupt or incompatible metadata rebuilds normally,
and
RUVYXA_DISABLE_ARTIFACT_CACHE=1provides a correctness-preserving temporary bypass. - Coordinated cache pressure — compiler memory, resolver derivations, and artifact metadata use
one soft/hard hysteresis policy (
RUVYXA_BUILD_CACHE_MEMORY_MB, 256 MiB default). Worker caches apply the same policy underRUVYXA_MEMORY_LIMIT_MB(512 MiB default), skip pinned build keys, stop speculative warmups at the hard limit, and expose pressure/eviction counters. - Config-declared request pipeline —
headers(),redirects(),rewrites(), andproxyon one config object, evaluated by the native host and every deployed build from one shared table. AST-based import/export extraction and CommonJS detection for npm dependencies. - Gzip + Brotli compression — all responses compressed automatically via tower-http middleware.
- ETag / 304 support — static assets include BLAKE3-256-based ETags for efficient browser caching. Bundle names are BLAKE3-content-addressed for deterministic cache busting.
- Hot Module Replacement — style and component updates streamed over WebSocket without full-page reloads. CSS collection, minification, and HMR are handled natively by the dev server.
- Debug overlay — in-browser error overlay during development with source-mapped stack traces.
- Dev/prod parity —
devandstartshare routing, rendering, static asset, security-header, and compression semantics. - Port conflict detection — auto-scans 100 subsequent ports with process-owner identification
(Windows
netstat/tasklist, Unixlsof).
- SSR-first React — pages render on the server with layout nesting, route-level client bundles for hydration, and the persistent worker pool.
- Five rendering strategies — SSR (default), SSG, ISR, CSR, and PPR. Configurable per-route via
ruvyxa.config.tsor inline exports (revalidate,ppr,getStaticParams,'use client'). - Partial Pre-rendering (PPR) — static shell with streamed dynamic slots via React
<Suspense>boundaries andonShellReadystreaming. - Incremental Static Regeneration (ISR) — stale-while-revalidate with configurable TTL.
- On-demand revalidation —
revalidatePath()fromruvyxa/serverqueues one URL for a fresh render on its next request from any API route or server action. For SSR and CSR the cached document is dropped; for SSG, ISR, and PPR the next request also bypasses the per-rendered HTML. The invalidation arrives with the write that caused it, so a client following the action cannot outrun the cache clear. Works indev,start, and serverless. getStaticParams— generate static paths at build time for dynamic SSG routes.- Deferred and zero-JS hydration — route exports accept
hydrate = 'visible','idle', orfalse. Deferred routes do not preload their React bundle; one small shared loader imports it only when the route becomes visible or the browser is idle.falseemits no client bundle at all. - Simple SSG parameters — export
staticParamsdirectly for known values, or return scalar values fromgetStaticParamswhen a route has one dynamic segment. Parameter discovery supports opt-in, dependency-aware persistent caching. - CDN-ready code splitting — route-level, shared, or vendor chunk splitting via
build.splitwith tree-shaking applied per-split.
- App directory router —
app/discoverspage.tsx,page.md,page.mdx,route.ts,layout.tsx,server.ts, andaction.tsautomatically. - Dynamic segments —
[param],[...catchAll], and[[...optionalCatchAll]]with full param access injected into loaders and page components. - Route groups —
(group)directories for logical organization without affecting the URL. - Parallel route slots —
@slot/directories for parallel-rendered route segments. - API routes — named HTTP-method exports (
GET,POST,PUT,DELETE,PATCH) inroute.tsfiles, with binary-safe response streaming through bounded worker IPC. - Duplicate & ambiguous route rejection — the graph validator catches conflicts before they reach production.
- Built-in content routes —
page.mdandpage.mdxsupport nested YAML frontmatter, stable heading exports, GFM tables/tasks/references/footnotes, multiline ESM, JSX member components, expressions, component overrides, and SSG. Same dev/prod pipeline as TSX routes. - Fast WebP image pipeline — production builds replace copied PNG/JPEG assets with cached, parallel-encoded WebP output for low CLS.
- Dependency-driven CSS imports — application modules import
.cssfrom anywhere; no separate import manifest required. - CSS entries for globals — unimported global stylesheets via
css.entriesin config. - SCSS/Sass built in — import
.scssand.sassfiles directly, including partials referenced with Sass@use,@forward, or@import. - CSS Modules —
.module.css,.module.scss, and.module.sassimports expose deterministic, project-scoped class maps to React components while emitting the matching collected CSS. - CSS-in-JS compatible — React style objects and
<style>elements work natively. - CSS caching & minification — production builds minify collected styles with cached results.
- Tailwind CSS auto-detection — detects
@import "tailwindcss"in stylesheets and invokes@tailwindcss/cliwith--minifyin production. LESS imports produce a clear diagnostic.
- Co-located data fetching — server-only
server.tsfiles beside routes withloader()andcache()utilities. - Real TTL caching — human-readable durations (
"30s","5m","1h","1d") withinvalidateCache(key)orinvalidateCache()(clear all) from server actions. Stale-while- revalidate keeps responses fast during background refresh.cacheStats()provides runtime observability ({ size, maxEntries }).
- Type-safe server actions —
action.input()with validation parser and.handler()with typed input and cache invalidation callback. - Content type support —
application/jsonandapplication/x-www-form-urlencoded. - Module isolation — actions run in isolated contexts with bounded resource usage.
- Error boundary —
<RuvyxaErrorBoundary>with typedfallback({ error, resetError })for per-route error isolation.resetError()clears state for retry without full-page reload. - Hydration —
hydrate()attaches React to server-rendered DOM with automatic error reporting and fallback rendering when hydration fails. - Image components —
<Image>(responsive,fill,priority,loader,unoptimized,fetchPriority) and<Picture>for art-direction with multi-source support. - SEO, GEO, and AEO primitives —
<Seo>with typed canonical, robots, Open Graph, Twitter Card, Article/Breadcrumb JSON-LD, plus a visible<Answer>primitive with citations and Question/Answer microdata. Production builds also emit standards-compliant, automatically shardedsitemap.xmland configurablerobots.txt, while public files or exact routes can take ownership. - Client loader hook —
useRuvyxaLoaderloads client-side data and returns{ data, loading, error, refetch }with built-in race-condition handling and mount-safety checks. See the client loader guide. - Typed routes — set
typedRoutes: trueanddev/build/checkgenerate.ruvyxa/types/routes.d.ts;<Link href>and the imperative router are then narrowed to the routes the project actually has, withroute(url)for URLs computed at runtime. Opt-in — until the file exists, the type collapses back to plainstring. <Script>— third-party scripts withbeforeInteractive,afterInteractive, andlazyOnloadstrategies; an external URL is fetched once per page.- Instrumentation — an optional
instrumentation.tswhoseregister()runs once per server process, for installing OpenTelemetry, error reporters, or metrics exporters.
- Server/client boundary enforcement —
server-only,client-only, andserver/imports are validated at build time. Private environment variables never leak to client bundles; onlyRUVYXA_PUBLIC_-prefixed variables are accessible on the client. - Server action guards — same-origin checks, Fetch Metadata guards, 1 MB body limit
(
security.actionLimit), 10 MB API body limit (security.apiLimit), and per-client/action rate limiting (600 req/min default viasecurity.actionRateLimit). - Security headers — native, standalone, and serverless responses receive the same seven safe
defaults while explicit application headers win. Static/Cloudflare
_headersoutput carries the same policy; CSP and HSTS remain explicit because safe values are application-specific. - Config safety — unknown configuration keys fail intentionally; typos never silently change deployment behavior.
- Tower-based middleware — composable CORS, timing, logging, rate limiting, and custom headers
via
ruvyxa.config.ts. Route-scoped middleware targets specific path patterns. - Route rules —
headers(),redirects(), andrewrites()with path-to-regexp sources andhas/missingconditions, applied in a fixed order ahead of routing on both hosts. proxy— one handler for the pathsproxy.matchernames: answer with aResponse, or continue with a rewrittenRequest. Runs in the project worker underruvyxa dev/startand in-process in every deployed build.- File conventions —
instrumentation.tsfor startup work,route.tsfor any generated file (security.txt, feeds, OpenAPI),content: truefor the content engine's artifacts. See the Request pipeline. - Official state packages —
@ruvyxa/databaseprovides a typed adapter facade,@ruvyxa/authprovides secure provider-driven sessions, and@ruvyxa/realtimeconnects opted-in server actions to the native self-hosted WebSocket transport with explicit deployment guards.
- 13 verified commands —
dev,build,check,start,preview,routes,analyze,adds,doctor,clean,trace,bench, andtest:parity. build— production output supports--target node,bun,edge, orstatic, plus--adapter <name>to run a deploy adapter without editing config and--server-onlyfor API-only artifacts. Pre-renders SSG, ISR, PPR, and CSR pages at build time via parallel worker pool (MAX_PRERENDER_PARALLELISM: 2).check— type checking, production build, dev/prod route parity, and page smoke rendering in one command.analyze— human, JSON, SARIF 2.1.0, or a self-contained interactive HTML validation report for routes, imports, and server/client boundaries (--format sarif --output reports/ruvyxa.sarif;--html).adds— scaffold an additive, framework-nativeform,data-table, orauthflow, or anaxumhost: aCargo.tomlandsrc/main.rsthat serve the static build from a Rust binary.doctor— project health plus deploy-target inspection: adapter runtime, platform, capabilities, and every route unsupported by the selected adapter (--jsonfor CI).bench— benchmark route discovery, analysis, validation, and production builds.test:parity— compare dev/prod routes and smoke-render page routes.- First-Class Diagnostics — Over 60
RUV####error codes spanning Boundary Violations (RUV1000s), Server/Render Errors (RUV1100s), Build/Compilation (RUV1300s), and Official Packages (RUV3000s). Every diagnostic carries its own explanation and suggested fix at the point it is raised; see Troubleshooting for the common symptoms and their evidence-backed fixes.
- Four starters —
npm create ruvyxa@latestdefaults to the focusedminimalapp, withblog,crud, andapiavailable through--template. Run it with no arguments on a real terminal and it prompts for a project name and offers an arrow-key template menu (j/kalso work); the scaffold summary prints the actual generated file tree, colored by role. - 11 Deployment Adapters — Zero-config native output for Vercel, Netlify, Cloudflare, Node.js, Bun, Deno, Static, AWS Amplify, Firebase, Railway, and Render. See the Deployment Guide for platform-specific configurations.
- Or your own Rust binary — the static target's publish directory is served by the
ruvyxa-axumcrate from anaxum::Router, with the_headerspolicy, the project's404.html, and the shared content-type table, so a Rust service deploys the site the way it deploys itself.
Version floors are declared once, in the manifests, and this table points at them rather than restating numbers that go stale:
| Use case | Requirement | Declared in |
|---|---|---|
| Building an app | Node.js (Bun can run SSR instead). No Rust toolchain needed — the CLI ships prebuilt. | engines.node in each published package.json |
| Supported CLI platforms | win32-x64, win32-arm64, linux-x64, linux-arm64, darwin-arm64 |
optionalDependencies of ruvyxa |
| Building the framework | Node.js, pnpm, and a Rust toolchain (edition 2024) | .nvmrc, packageManager, rust-version |
| Serving from your own Rust binary | Node.js to run ruvyxa build; a Rust toolchain for your application; nothing on the host at runtime |
rust-version in the workspace Cargo.toml |
ruvyxa doctor prints the versions it actually resolved on your machine and says which ones are too
old, which is the answer that matters more than any number written here.
The ruvyxa npm package resolves one @ruvyxa/cli-<platform> optional dependency that carries the
prebuilt native binary, so npm install is all that is required to get a working ruvyxa command.
npm create ruvyxa@latest my-app
cd my-app
npm install
npm run devChoose a focused starter when you want more than the minimal route:
npm create ruvyxa@latest my-blog -- --template blog
npm create ruvyxa@latest my-admin -- --template crud
npm create ruvyxa@latest my-api -- --template apiOpen http://localhost:3000.
pnpm, yarn, bun, and Deno tasks work too. When no runtime is configured, Ruvyxa prefers Node,
then falls back to Bun and Deno. Set runtime: 'bun' or runtime: 'deno', or pass
--runtime bun|deno, when that runtime should execute config, SSR, API routes, actions, adapters,
and the project worker. Deno local tooling runs with the permissions required by trusted project
config (-A --no-prompt). A scaffold can be run with deno install && deno task dev. The generated
app keeps the first screen focused:
my-app/
├── app/
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── public/
│ └── ruvyxa.png
├── package.json
├── ruvyxa.config.ts
└── tsconfig.json
In practice you rarely type ruvyxa directly — every starter wires the CLI into package.json
scripts, so the day-to-day loop is plain npm/pnpm/yarn/bun scripts:
| Script | Runs | When you use it |
|---|---|---|
npm run dev |
ruvyxa dev |
Local development with HMR |
npm run build |
ruvyxa build |
Production build into .ruvyxa/ |
npm start |
ruvyxa start |
Serve the production build |
npm run preview |
ruvyxa preview |
Check the production build locally |
npm run check |
ruvyxa check |
Pre-deploy gate: typecheck + build + parity |
npm run routes |
ruvyxa routes |
See what the router discovered |
npm run analyze |
ruvyxa analyze |
Boundary/import validation, CI-friendly |
npm run doctor |
ruvyxa doctor |
Environment and deploy-target health |
npm run adds -- form |
ruvyxa adds form |
Scaffold a framework-native flow |
npm run trace -- / |
ruvyxa trace / |
Inspect one route manifest entry |
npm run clean |
ruvyxa clean |
Remove .ruvyxa/ |
Arguments after npm run <script> need the -- separator (npm run trace -- /blog/[slug]); pnpm
and bun pass them through directly. ruvyxa has no --version flag — run ruvyxa doctor, which
prints the resolved version alongside the rest of the project report.
With a Rust backend, add the axum host to the same project and build for the static target:
npm run adds -- axum # Cargo.toml and src/main.rs beside package.json
npm install @ruvyxa/adapter-static # then `adapter: staticOutput()` in ruvyxa.config.ts
npm run build # writes .ruvyxa/static
cargo run # serves it, and /api/health, on port 3000The result is one binary with nothing else installed on the host. What it can and cannot serve is in one binary for the site and the API.
First time using Ruvyxa? Check out the Tutorial: Build a Mini Blog in the Getting Started guide for a step-by-step introduction to Routing, Server Components, and Dynamic Routes.
For a fuller integration app with dynamic routes, API routes, server actions, and all rendering strategies, see examples/demo.
Measured on 2026-08-21 with the repository harness against minimal starters. These figures are valid only for the exact versions, machine, and run conditions shown below; re-run the harness when comparing newer releases.
| Metric (lower is better) | Ruvyxa 1.1.0 | Next.js 16.3.0 | Astro 7.2.4 |
|---|---|---|---|
| Production build (cold-cache median) | 1.131 s | 7.667 s | 2.309 s |
| Dev server → first rendered response | 1.115 s | 3.310 s | 5.855 s |
| Prod server start → first response | 0.845 s | 1.074 s | 2.813 s |
| Client JS shipped (minimal page) | 235 KB ¹ | 568 KB | 0 KB ² |
| Throughput (higher is better) | Ruvyxa 1.1.0 | Next.js 16.3.0 | Astro 7.2.4 |
|---|---|---|---|
Requests/second (/, prod server) ³ |
44,528 | 3,647 | 3,611 |
| Latency p50 / p99 | 0 / 1 ms | 6 / 12 ms | 6 / 10 ms |
In this run, Ruvyxa's median cold build completed 6.8× / 2.0× faster than Next.js / Astro respectively, dev-server readiness was 3.0× / 5.3× faster, production-server readiness 1.3× / 3.3× faster, and the measured production throughput was 12.2× / 12.3× higher. These are local results for this minimal-starter workload, not a universal performance ranking.
First-run warm-up is real and large enough to swamp a careless reading: Next.js's first cold build measured 19.8 s against a 7.6 s median for its other two runs, and Astro's first spiked to 20.2 s against a ~2.2 s median. The reported medians are unaffected because a median discards one outlier; Ruvyxa's three cold builds were 1.175 s / 1.128 s / 1.131 s, which is the spread worth noting on its own. Re-run the harness on an otherwise idle machine before reading anything into small differences, and treat gaps under ~100 ms as noise.
¹ For the interactive React starter page. A content page can opt out entirely with
export const hydrate = false — its HTML then ships 0 KB of JavaScript and no client bundle is
emitted. ² Astro's minimal starter is a zero-JS static page by design (no React hydration), so it
has no client bundle and its preview server serves static files only. ³ The harness runs
autocannon once for 10 seconds with 25 connections against the final production server of each
framework; throughput and latency are not medians.
Methodology — measured on Windows 11 Home, AMD Ryzen 7 8845HS, 31 GB RAM. Each framework used a
freshly scaffolded minimal starter in an isolated benchmark root with RUNS=3 and the same
scripts/bench-frameworks.mjs harness. The harness reports timings
only, not framework versions; capture those from each starter's own lockfile at the moment you run
it, because that is the only record that will still be accurate later. Build = build script wall
time. Dev/prod readiness = time from process spawn to first HTTP 200 on /. Cold-cache runs remove
.ruvyxa/.next/dist/.astro/Vite caches before each run; dependencies remain installed during
the harness. The Ruvyxa column was packed from this repository with pnpm pack:smoke and installed
from local tarballs together with the matching Windows native CLI package, rather than installed
from the npm registry; the Ruvyxa and Next starters ran the same React. The machine was not
otherwise idle during this run, so the absolute readiness and build timings run slightly high; the
three frameworks were measured back to back under the same conditions, so the comparison between
them holds. To reproduce, prepare the three isolated starters, use local tarball overrides for an
unpublished Ruvyxa release candidate, then run
BENCH_ROOT=<benchmark-root> RUNS=3 node scripts/bench-frameworks.mjs.
./setup.sh
cargo run -p ruvyxa_cli -- dev --root examples/demoOn Windows, use setup.bat instead of ./setup.sh. The setup script installs locked dependencies,
builds workspace packages, and compiles the Ruvyxa CLI.
Build and test all packages:
cargo test --workspace
pnpm -r build
pnpm -r check
pnpm -r testStandalone JavaScript and TypeScript tests live under tests/ and are routed by each package's
test script. See Development & Testing for the verification
layout.
The full pre-submit gate used in this repository:
cargo fmt --all -- --check
cargo clippy --workspace --locked -- -D warnings
cargo test --workspace --locked
pnpm -r build && pnpm -r check && pnpm -r test
pnpm format:check
pnpm release:validate
pnpm pack:smoke
cargo run -p ruvyxa_cli -- check --root examples/demoruvyxa/
├── crates/ # Rust workspace (8 crates)
│ ├── ruvyxa_cli/ # commands, config loading, build orchestration
│ ├── ruvyxa_bundler/ # TS/JSX compile, resolve, link, minify, source maps
│ ├── ruvyxa_dev_server/ # axum server, HMR, worker pool, router, caches
│ ├── ruvyxa_graph/ # route discovery, validation, render strategies
│ ├── ruvyxa_middleware/ # Tower layers, route rules, worker host
│ ├── ruvyxa_diagnostics/# RUV#### structured errors
│ ├── ruvyxa_tui/ # terminal layout, progress, mascot, and theme primitives
│ └── ruvyxa_axum/ # `ruvyxa-axum` on crates.io: serve the static build from axum
├── packages/ # npm packages (see the table below)
├── templates/ # create-ruvyxa starters
├── examples/demo/ # 23-route integration fixture
├── tests/ # Node tests, organized by package
├── docs/{en,th}/ # user-facing manual, both editions
└── scripts/ # release validation, packing, benchmarks
Routes are discovered from app/. Every page.tsx must export a default component; every
route.ts exports named HTTP-method handlers.
The folder name is the complete route contract: use [slug] for one segment, [...path] for a
required string[], and [[...path]] for an optional string[]. Route groups ((...)) organize
files without adding a segment. There is no separate :param or *param route syntax to configure.
Directories starting with _ or @ are ignored.
export default function Home() {
return <main>Hello Ruvyxa</main>
}Co-locate server-only data fetching beside routes via server.ts:
import { loader, cache } from 'ruvyxa/server'
export const getPost = loader(async ({ params, cache, request }) => {
return cache(`post:${params.slug}`)
.ttl('5m')
.get(async () => {
return db.posts.findBySlug(params.slug)
})
})The cache() utility provides real in-memory TTL caching with human-readable durations ("30s",
"5m", "1h", "1d"). Call invalidateCache(key) or invalidateCache() (clear all) from server
actions.
Co-locate validated mutations beside routes via action.ts:
import { action } from 'ruvyxa/server'
export const createTodo = action
.input({
parse(value: unknown) {
if (!value || typeof value !== 'object' || !('title' in value))
throw new Error('Title is required')
return { title: String(value.title).trim() }
},
})
.handler(async ({ input, invalidate }) => {
invalidate('todos')
return { title: input.title, completed: false }
})Supported content types: application/json, application/x-www-form-urlencoded.
Security defaults: body size limit (1 MB), API body limit (10 MB), same-origin check, Fetch Metadata guards, per-client/action rate limiting (600 req/min), module isolation.
Ruvyxa ships a tower-based middleware system configurable via ruvyxa.config.ts, and a proxy that
runs ahead of the routes its matcher names:
import { config } from 'ruvyxa/config'
export default config({
middleware: { builtin: { timing: true, log: true } },
proxy: {
matcher: '/api/:path*',
handler(request) {
return request.headers.has('authorization')
? undefined
: new Response('Unauthorized', { status: 401 })
},
},
})Built-in middleware stays native Tower code. proxy.matcher is compiled natively on both hosts;
proxy.handler runs in the persistent project worker under ruvyxa dev/start, bounded by
middleware.timeoutMs, and in-process in every deployed build.
CSS imports are dependency-driven, so application modules may import .css from anywhere inside the
project. Use css.entries below for global files or directories that are not imported; React style
objects and <style> elements continue to work for runtime CSS-in-JS.
import { config } from 'ruvyxa/config'
export default config({
appDir: 'app',
outDir: '.ruvyxa',
css: {
entries: ['styles/theme.css'],
},
server: {
host: 'localhost',
port: 3000,
},
build: {
minify: true,
map: false,
treeShake: true,
split: 'route',
jsx: 'automatic',
target: 'es2022',
workers: 4,
manifest: false,
warm: true,
},
render: {
strategy: 'ssr',
revalidate: 60,
},
cache: {
routes: true,
css: true,
dir: '.ruvyxa/cache/bundler',
},
debug: {
overlay: true,
traces: true,
},
image: {
optimize: true,
quality: 82,
lossless: false,
variantWidths: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
workers: 0,
},
security: {
actionLimit: 1024 * 1024,
apiLimit: 10 * 1024 * 1024,
actionRateLimit: { max: 600, window: 60 },
sameOrigin: true,
fetchMeta: true,
trustedProxyIps: [],
headers: true,
},
middleware: {
builtin: {
timing: true,
log: true,
cors: {
origins: ['http://localhost:5173'],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
credentials: true,
},
},
},
})| Strategy | Export | Behavior |
|---|---|---|
| SSR | default | Rendered per request (default) |
| SSG | staticParams / config |
Pre-rendered at build time, served as HTML |
| ISR | export const revalidate |
Stale-while-revalidate with configurable TTL |
| CSR | 'use client' directive |
Minimal shell, full render in browser |
| PPR | export const ppr = true |
Static shell + streamed dynamic slots |
Dynamic routes can export a staticParams array for known values or use getStaticParams(context)
for asynchronous discovery. getStaticParams may return { params, cache: '10m' } to persist the
result until its TTL expires; changes to the route or imported dependencies invalidate it early. See
the rendering guide for scalar shorthand, context, and cache
examples.
Fourteen commands. Project commands accept --root <dir> (default .) and
--runtime node|bun|deno.
| Command | Purpose | Additional flags |
|---|---|---|
ruvyxa dev |
Development server with HMR and file watching | --host, --port |
ruvyxa build |
Build production output to .ruvyxa/ |
--target node|bun|deno|edge|static, --adapter, --server-only |
ruvyxa check |
Production readiness gate: typecheck, build, dev/prod parity, page smoke render | — |
ruvyxa start |
Serve production output with the same runtime semantics as dev | --host, --port |
ruvyxa preview |
Preview an existing production build locally (same server as start) |
--host, --port |
ruvyxa routes |
Print the discovered route table | --json |
ruvyxa analyze |
Validate routes, imports, and server/client boundaries | --format auto|human|json|sarif|html, --output, --html |
ruvyxa adds <flow…> |
Scaffold a form, data-table, or auth flow |
--force |
ruvyxa doctor |
Project health plus deploy-target inspection | --target, --adapter, --json |
ruvyxa trace <route> |
Inspect one route manifest entry | — |
ruvyxa bench |
Benchmark route discovery, analysis, validation, and production builds | --runtime, --samples <n> (default 3), --json, --baseline |
ruvyxa test:parity |
Compare dev/prod routes and smoke-render page routes | — |
ruvyxa clean |
Remove .ruvyxa/ build output |
— |
trace takes a route manifest path, not a request URL: use ruvyxa trace "/blog/[slug]", not
ruvyxa trace /blog/hello. It prints the route id, file, layout chain, server/client modules,
runtime, and render strategy as JSON. On Windows, quote paths containing [ ], and note that Git
Bash rewrites a leading / into a Windows path — use PowerShell, cmd, or MSYS_NO_PATHCONV=1.
Command and flag spellings are normalized before parsing, so --root=x, --server_only,
test-parity, and an em-dashed —root all resolve to their canonical form. Run
ruvyxa help <command> for the built-in reference. There is no --version flag; ruvyxa doctor
reports the resolved version.
Use ruvyxa bench --baseline --json for the production baseline. Each sample copies project inputs
into an ignored temporary workspace and measures cold/warm builds, first-route rendering, and
CSS/client/server/leaf edit classes. Results use the stable ruvyxa.build-bench contract with a
separate schemaVersion: 1, plus peak resident memory and HMR reload-fallback counts. The command
refuses to publish timings unless cold and warm builds have the same semantic artifact set;
cache/timing telemetry is excluded from that comparison, while deployed code, assets, and manifests
remain part of it. The ordinary bench --json array is unchanged for existing consumers.
Every command in the table above was run on 2026-08-24 against examples/demo — 30
routes: 27 pages and 3 API routes — with a --release binary built from this working tree.
Scaffolding commands ran against a throwaway copy of templates/minimal so the fixture stayed
clean. Timings are one machine's, not a specification; re-run them rather than quoting them.
| Command | Observed result |
|---|---|
routes |
30 routes discovered (27 pages, 3 API), strategy resolved per route |
doctor |
0 diagnostics, adapter ruvyxa-native, every route supported by the target, 1.17s |
analyze |
0 diagnostics; 38 client modules and 4 server modules reported |
trace |
route id, file, layout chain, runtime, and render strategy as JSON |
build |
cold build of all 30 routes into .ruvyxa/ in 8.15s, 247 kB shared by every page |
start |
ready in 425ms; GET /, GET /api/health, and GET /blog/hello-world all → 200 |
preview |
ready and serving the same production build → 200 |
dev |
ready in 482ms with HMR enabled; GET / → 200 |
check |
typecheck + build + parity + smoke render over 30 routes, 16.01s, exit 0 |
test:parity |
parity passed for 30 routes in 14.40s, exit 0 |
bench |
6 scenarios; cold build 8.27s against warm 657ms — 92% of it saved by the cache |
adds |
form wrote page.tsx + action.ts; data-table wrote the generic client component |
clean |
removed .ruvyxa/ in 141ms |
┌───────────────────────────────────────────────────────────────┐
│ ruvyxa (npm package) │
│ CLI launcher → Ruvyxa CLI Rust binary (ruvyxa_cli) │
│ Runtime: worker-pool.mjs (persistent Node/Bun/Deno IPC) │
└─────────────────────┬─────────────────────────────────────────┘
│
┌─────────────────────┴─────────────────────────────────────────┐
│ Rust Workspace (crates/) │
├─────────────────────┬─────────────────────────────────────────┤
│ ruvyxa_bundler │ compiler, minifier, linker, resolver, │
│ │ source maps, boundary checks │
│ ruvyxa_cli │ CLI commands, config loading, build │
│ │ orchestration, production output │
│ ruvyxa_dev_server │ axum server, websocket HMR, worker │
│ │ pool, radix router, render cache │
│ ruvyxa_middleware │ Tower layers, route rules, worker host │
│ ruvyxa_graph │ route discovery, import graph, render │
│ │ strategy detection, validation │
│ ruvyxa_diagnostics │ structured errors with RUV#### codes │
│ ruvyxa_axum │ ruvyxa-axum on crates.io: the static │
│ │ build served from your own axum app │
└─────────────────────┴─────────────────────────────────────────┘
Performance features:
- Persistent JavaScript worker pool (eliminates 100-500ms/request subprocess overhead)
- Radix-trie route matching (O(depth) instead of O(n))
- LRU render cache with TTL (sub-ms repeated page loads)
- Bounded, binary-safe API response streaming across worker IPC
- Async file I/O via tokio::fs (no thread starvation)
- SSR via
renderToStringwith layout nesting - Gzip + Brotli compression (tower-http)
- ETag / 304 Not Modified (BLAKE3-256 hashing)
- RwLock-based runtime cache (concurrent readers)
- Route-level client bundle splitting with tree-shaking
.ruvyxa/
├── server/ # Production route source (copied from app/, components/, server/)
├── client/ # BLAKE3-hashed client bundles + manifest.json
├── assets/ # Public assets + converted WebP images and image manifest
├── prerender/ # Pre-rendered SSG/ISR/PPR/CSR HTML files + manifest.json
├── manifest.json # Route manifest with paths, layouts, module references
└── build.json # Build metadata, security defaults, build settings, render summary
Hybrid adapters add platform deployment directories containing a compiled .mjs static route
registry. Serverless and edge handlers execute that bundle directly; raw TS/TSX source is not used
as a deployment entrypoint.
| Package | Description |
|---|---|
ruvyxa |
CLI, runtime bridge, and public framework entrypoints |
create-ruvyxa |
Minimal app scaffolder (4 starters) |
@ruvyxa/core |
Typed config, server APIs, cache helpers, responses, and adapter contracts |
@ruvyxa/react |
React components, hooks, SEO, error boundary, hydration |
@ruvyxa/auth |
Provider-driven authentication (credentials, GitHub, Google, magic link) |
@ruvyxa/database |
Typed database adapter facade (Prisma, DynamoDB) |
@ruvyxa/realtime |
WebSocket transport for opted-in server actions |
@ruvyxa/testing |
Dependency-free loader, action, and cache test doubles |
@ruvyxa/adapter-node |
Node deployment adapter |
@ruvyxa/adapter-vercel |
Vercel serverless adapter |
@ruvyxa/adapter-cloudflare |
Cloudflare edge adapter |
@ruvyxa/adapter-netlify |
Netlify functions adapter |
@ruvyxa/adapter-bun |
Bun runtime adapter |
@ruvyxa/adapter-deno |
Deno self-hosted runtime adapter |
@ruvyxa/adapter-static |
Static output adapter |
@ruvyxa/adapter-railway |
Railway standalone service adapter |
@ruvyxa/adapter-render |
Render Web Service and Blueprint adapter |
@ruvyxa/adapter-firebase |
Firebase Hosting and Cloud Functions v2 adapter |
@ruvyxa/adapter-aws |
AWS Amplify Hosting static and compute adapter |
ruvyxa also resolves one of five @ruvyxa/cli-<platform> packages as an optional dependency. They
carry the prebuilt native CLI for a single target and are not imported directly.
One crate is published outside npm: ruvyxa-axum on crates.io, which serves a
static build from an axum::Router and is what ruvyxa adds axum writes into a project's
Cargo.toml. It depends on nothing else in the workspace.
See CONTRIBUTING.md for local setup, verification commands, and release rules.
Apache 2.0 Copyright (c) 2026 Thirawat Sinlapasomsak
