Project structure
A Verve application is the framework tree — verve-cli new copies the framework source into your project and your code slots into designated directories. There is no package-manager indirection: you can read (and step-debug) every layer you run on.
myapp/
├── build.zig framework build: server, wasm client, codegen
├── build.zig.zon package identity (name, fingerprint, paths)
├── src/
│ ├── app/ ← YOUR application
│ │ ├── api.zig module root: exports routes, Actions, islands
│ │ ├── routes.zig route table (Route.init / Route.layout)
│ │ ├── components.zig page components (page shell, 404, error)
│ │ └── islands.zig island registry (Props contracts)
│ ├── client/
│ │ ├── islands/ ← YOUR island implementations (one .zig per island)
│ │ └── ... wasm runtime (framework)
│ ├── core/ reactive core, router, renderer, viz/anim/gl
│ ├── server/ HTTP server, api handler, push channels
│ ├── desktop/ native window hosts (macOS/Linux/Windows)
│ └── bridge/verve.js ~minimal JS glue the client wasm talks through
├── tools/ build-time codegen (island manifest, server fns)
└── public/ static assets (opt-in via -Dpublic-dir=public)The four app files
src/app/api.zig — module root
The build wires this file as the app module. It re-exports the other three and declares Actions — every public function in that struct becomes a typed /api/<fn> endpoint:
pub const components = @import("components.zig");
pub const islands = @import("islands.zig");
pub const routes = @import("routes.zig").routes;
pub const Actions = struct {
pub fn getCount(_: struct {}) !i32 { ... }
};src/app/routes.zig — route table
pub const routes: []const verve.Route = &.{
verve.Route.init("/", renderHome),
verve.Route.init("/work/:slug", renderWork),
verve.Route.layout("/app", renderShell, &.{
verve.Route.init("/dashboard", renderDash),
}),
verve.Route.init("/admin", renderAdmin).protect(adminGuard),
};src/app/components.zig — page components
Functions from *verve.Context to *verve.Node. The server calls three by name: page (shell), notFound, and errorPage.
src/app/islands.zig — island registry
Each pub const <Name> = struct { ... } declares an island the build discovers at configure time. The matching implementation lives at src/client/islands/<Name>.zig and compiles to its own island_<name>.wasm chunk. See Islands.
Build pipeline
zig build runs several phases around your code:
- Island discovery — parses
islands.zig, generates the client manifest mapping island names to wasm chunk URLs. - Server-fn codegen — walks
Actions, generates/api/<fn>dispatch plus typed client-side stubs (app_client.<fn>_call). - WASM compile —
client.wasm(main runtime) and one chunk per island,wasm32-freestanding,ReleaseSmall. - Asset embedding —
-Dpublic-dirfiles are embedded with content-type detection and hash-busted URLs (ctx.assetHref). - Server compile — native binary with everything baked in. One file deploys the whole site.
Next: The CLI.