Voyd is a statically typed language that compiles to WebAssembly. Write servers, browser apps, and shared logic in one expressive language—with practical effects and a first-party web stack.
Voyd includes typed routes, request extraction, middleware, static files, and server-rendered HTML. VX uses a typed model, message, and update loop for browser interfaces, and renders the same virtual tree on the server. Application models and logic can be shared across both.
On the server
Value-returning handlers and typed request data.
In the browser
Elm-inspired UI with JSX-like markup.
Between them
One type system for shared application logic.
app.voyd
use pkg::web::alluse std::error::HostErroruse std::http::serveruse std::result::types::alluse std::task::self as tasksuse std::vx::allfn home() -> Response html_response<Unit>( Response::ok(), <main> <h1>Built with Voyd.</h1> <p>One language, front to back.</p> </main> )pub fn main(): (server::HttpServer, tasks::TaskRuntime) -> Result<Unit, HostError> serve(port: 3000) routes(): get("/") do: home()
02Effects
Type-check side effects, too
A strong data type system catches mistakes in values and interfaces. Voyd’s effect system also tracks what functions can do, such as reading a file, calling a service, or using the clock, and checks that those effects are handled. Effect rows are inferred and polymorphic, so higher-order code remains reusable without passing annotations through every layer.
Catch more at compile time
Required capabilities stay visible in public APIs.
Inferred, not threaded
Most local code does not need effect annotations.
Test with handlers
Replace I/O at the boundary without reshaping domain code.
orders.voyd
@effect(id: "app.orders")eff Orders save(tail, order: Order) -> OrderIdfn checkout(order: Order): Orders -> Receipt let id = Orders::save(order) Receipt { order_id: id }// The callback's effects are inferred and preserved.fn run_twice<T>(work: fn() -> T) -> Array<T> [work(), work()]
03Types
A strong, expressive type system
Voyd combines local inference with traits, constrained generics, structural data, objects, and precise function types. These tools make it possible to describe application invariants without adding type annotations to every expression.
Model invariants
Put domain rules into reusable constraints.
Shape exact APIs
Use nominal or structural types as the boundary needs.
Voyd pairs concise expressions with labeled parameters, overloads, trailing closures, and uniform function-call syntax. The goal is to make APIs readable while keeping control flow explicit.
Clear at the call site
Labels explain roles when names alone cannot.
Easy to compose
Functions and methods share one consistent model.
Low on punctuation
The important parts of the program stand out.
geometry.voyd
fn add(a: i32, b: i32) = a + bfn add(a: f64, b: f64) = a + bfn move({ from: Vec, to destination: Vec }) send_move_instruction(from, destination)let point = Vec { x: 1, y: 2 }let moved = point.add(Vec { x: 3, y: 5 })move(from: point, to: moved)
05Embedding
Embeddable by design
Voyd can be compiled from Node, the browser, or Deno for extensions, sandboxed plugins, and generated programs. WebAssembly provides the runtime boundary, while the host decides which capabilities are available.
Compile in process
Use the public SDK without a separate toolchain.
Bring your own modules
Inject package source for extension systems.
Control the boundary
Expose only the host operations your product allows.