Journey: One-File Full-Stack Data
Journey: One-File Full-Stack Data
Section titled “Journey: One-File Full-Stack Data”The Duplicate Tax of Modern Web Dev
Section titled “The Duplicate Tax of Modern Web Dev”To build a simple “Todo list” or display a database record in most modern apps, you must duplicate the data structure across three distinct layers:
- The Database: A SQL migration or Prisma schema (
table tasks...). - The Backend ORM: The structure logic bridging the DB to logic (e.g., a Rust struct).
- The API Layer: An Express/Axum HTTP endpoint to serialize the struct into JSON.
- The Frontend: A TypeScript
interface Task { id: string, title: string }mirroring the query output.
This causes extreme friction when a single field changes, breaking APIs and forcing developers to jump through five files for the smallest data adjustment.
The Vox Paradigm: No API Layer
Section titled “The Vox Paradigm: No API Layer”Vox enables you to declare this from one single source of truth. One @table definition compiles into the correct Rust struct and the SQLite bindings. One @endpoint function creates an Axum handler and the matching TypeScript serialization client (vox-client.ts). A component declaration then directly calls the server function as if it was native to the React client.
You avoid writing boilerplate. State synchronization and type-checking happen safely across the entire vertical stack at compilation time.
Core Snippet: The Vertical Slice
Section titled “Core Snippet: The Vertical Slice”Below is a complete, working React frontend and Rust backend in a single .vox file.
// vox:skipimport react.use_state
// 1. DDL & Struct defined once entirely.@table type Task { title: str done: bool owner: str}
// 2. Server mutation automatically generated. Typed args enforce contract.@endpoint(kind: server) fn complete_task(id: Id[Task]) to Result[Unit] { db.Task.update(id, { done: true }) return Ok(())}
// 3. UI logic emitted as a plain React component (TSX) for the external frontend.component TaskList(tasks: list[Task]) { view: <div class="task-list"> {tasks.map(fn(task) { <label> <input type="checkbox" checked={task.done} onChange={fn(_e) complete_task(task.id)} /> {task.title} </label> })} </div>}
// Server Side Routing mapped directly to the UI elements.routes { "/" -> TaskList}Running the Process
Section titled “Running the Process”-
Put the code in
src/main.vox. -
Initialize and run:
Terminal window vox build src/main.vox -o distvox run src/main.vox -
Vox will instantly compile the
Tasktype into a Rust struct, create the SQLite table automatically via Codex, launch the Axum server, and compile the React bundle.
Maturity and limitations
Section titled “Maturity and limitations”- Maturity:
beta— web stack and Codex bindings are active development surfaces; verify against golden examples for your compiler version. - Limitation ids: L-021 (workspace-local vs canonical Codex stores can diverge if env paths are mis-set).
Deep Dives
Section titled “Deep Dives”To examine how the compiler handles this transparently:
- Compiler Architecture Details
- ADR 010 — TanStack as the Vox Web Spine: Why React components generated by Vox use TanStack Query underneath to maintain reactive state without loading screens.
- External Frontend Interop Plan 2026: How an external React app imports Vox-emitted components and calls Vox endpoints over the generated
vox-client.ts. - Explanation: Vox Web Architecture and TypeScript Interop: SSOT explaining the compilation boundaries between Vox AST and
.tsxfile emission.