sirhcosirhco.dev

verve · open source

Full-stack web in pure Zig.

SSR with fine-grained reactivity, per-island WASM code splitting, single-binary deploy. No VDOM. No macros. No third-party dependencies. Targets Zig 0.16.

the bet

SSR-first.

Pages render server-side as Node trees streamed straight to the socket. Search engines and noscript clients see real content. No hydration handshake required to read the page.

Real reactivity.

The same Signal / Effect / Owner / Resource graph the server uses ships into a wasm32-freestanding client runtime. DOM updates are a consequence of Signal.set — not a parallel write path tacked on for interactivity.

One binary.

No Node runtime. No build server. No bundler config. zig build produces a single executable with the WASM client, per-island chunks, JS bridge, public assets, and manifest baked in. Deploy by scp.

what's in the box

Routing + rendering

  • Comptime route parser with path params, wildcards, nested layouts.
  • ProtectedRoute guards + Redirect sentinel.
  • useLocation, RequestMeta (cookies, Accept-Language, etc).

Reactivity (server + WASM)

  • Signal / Effect / Store / Resource — SolidJS-style runtime.
  • Owner tree with on_cleanup, untrack, batch.
  • Keyed-list reconciler with LIS-based diff planner.

Head + components

  • setTitle / metaTag / linkTag / jsonLd with priority + replace-not-append.
  • provide / use DI through the owner chain.
  • show / forEach / portal — control-flow helpers.

Auth + security

  • CSRF HMAC-SHA256, auto-issued cookie + __csrf field.
  • Per-request CSP nonce stamped onto every <script> / <style>.
  • Origin pinning, SameSite=Strict on the CSRF cookie.

SSR + client

  • Streaming SSR over std.http.Server, chunked transfer-encoding.
  • Typed server-fn client stubs generated at build time.
  • Out-of-order Suspense streaming with <template> drains.

Islands

  • Per-island WASM chunks, ~73 B each via shared linear memory.
  • Build-time manifest codegen walks app.islands at comptime.
  • Lazy JS bridge fetches each chunk on first encounter.

Assets + i18n

  • Static asset routing at /public/* — runtime or comptime-embedded.
  • Hashed URLs with immutable Cache-Control headers.
  • I18nCatalog + resolveLocale (cookie → query → Accept-Language).

Dev + ops

  • --dev auto-reload via WS-disconnect-reconnect.
  • /events SSE + /ws bidirectional WebSocket.
  • /health + /metrics, per-connection worker pool, systemd socket activation.

install

Three commands, one binary.

Prebuilt binaries ship for linux and macos on x86_64 and aarch64. From source it is exactly one tool — zig — and one build file.

zig version                              # expect 0.16.0
zig build                                # native server + WASM client + per-island chunks
./zig-out/bin/verve-server               # http://127.0.0.1:8080

Docs: github.com/sirhco/verve/tree/main/docs. Showcase example exercises every public export.

live demos

This page runs on Verve.

The counter below is an island. The framework ships a small WASM chunk fetched on demand, shares linear memory with the main client, and hydrates the bound span. Clicks below are real Actions: each form POSTs to /api/<name>, the framework verifies the CSRF token from the cookie + hidden field, calls the typed Zig function, and the redirect-back reflects the new value.

01 · island + actions

count6

counter island · WS push · zero reload

02 · always-on infrastructure

Every Verve server ships /events (SSE), /ws (WebSocket), /health, and /metrics by default — no setup, no extra deps. Open a second tab to /events and you'll see a 1s tick from the same binary that served this page.

open source · pre-1.0

github.com/sirhco/verve

background reading

Why I write Zig covers the language case. the Verve case study covers the framework decisions.