Journey: One-File Full-Stack Data
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
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 @server function creates an Axum handler and the matching TypeScript serialization client. The @island component 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
Below is a complete, working React frontend and Rust backend in a single .vox file.
// vox:skip
import 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.
@server fn complete_task(id: Id[Task]) -> Result[Unit] {
db.Task.update(id, { done: true })
return Ok(())
}
// 3. UI logic generated as React component.
@island
fn TaskList(tasks: list[Task]) -> Element {
let (items, _set_items) = use_state(tasks)
<div class="task-list">
{items.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
-
Put the code in
src/main.vox. -
Initialize and run:
vox build src/main.vox -o dist vox 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
- 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
To examine how the compiler handles this transparently:
- Compiler Architecture Details
- ADR 010 — TanStack as the Vox Web Spine: Why React islands generated by Vox use TanStack Query underneath to maintain reactive state without loading screens.
- Explanation: Vox Web Architecture and TypeScript Interop: SSOT explaining the compilation boundaries between Vox AST and
.tsxfile emission.