Inside the one binary.

Technical · 2026-08-22 · How a web server, a language VM, a SQL database and a JavaScript engine become a single file — and the three design decisions that make it behave under load.

The bill of materials

RingServ has zero dependencies because its dependencies are inside it, vendored source by source, pinned commit by commit, and compiled together by Andrew Kelley and the Zig team's Zig: Mahmoud Fayed and the Ring team's Ring VM — the same version 1.27 that RingScript compiles to WebAssembly, here compiled natively; Karl Seguin's http.zig in front; D. Richard Hipp's SQLite underneath, in WAL mode; the QuickJS-ng engine (Fabrice Bellard's QuickJS, community-maintained) as the JavaScript guest; and Youssef Saeed's tree-sitter-ring grammar, which lets ringserv check find mistakes without running anything.

Nothing is fetched at build time. zig build on a clean clone touches the network zero times — which is also why the supply-chain audit of a RingServ deployment is: read one file.

Decision one: N virtual machines, not one

HTTP threads never touch the VM. Requests are queued to N worker threads, each owning a private Ring VM — state is per-worker and thread-local, so there is no lock around your code and a slow request delays one worker, not the server. The workers proved out at roughly 9,500 evaluations per second on eight threads with zero corruption before anything was built on them, and the whole server holds ~5,700 requests/s at peak with four.

Decision two: many readers, one writer

Every worker reads the database concurrently; writes go through a single writer, one well-planned transaction at a time. That sounds like a bottleneck and measures like a feature: a write costs about a read (0.94 vs 0.78 ms), while the naive way — open, write, commit per statement — cost 10.13 ms on the same path. The single writer is also what makes exactly-once delivery for offline sync a property of the database rather than of hopeful control flow: a change's claim and its work commit together or not at all.

Decision three: the guest is a peer, not a plugin

A .js service runs on QuickJS-ng inside the same process, behind the same request contracts and the same placement rules as a Ring service, and calls Ring services by name. Two details cost real engineering: replies cross the boundary as the guest's own JSON, carried verbatim to the wire — Ring has no false and no null, and re-encoding used to quietly turn one into 0 and the other into ""; and the guest is measured, not assumed: 0.69 ms per action against Ring's 0.75.

How we know any of this is true

The claim "it runs Ring" is tested by running ~970 programs — Ring's official samples and every code block in Ring's documentation — through RingServ and through native Ring, and comparing output character by character, on every change, on Linux, macOS and Windows. The documentation is held to the same standard: the guides' own examples are extracted from the pages and executed, so prose that stops being true stops the build. 625 tests, about seventy seconds, run constantly.

The first three-platform run was not a formality, and we published what it caught — a cross-compile that had been silently broken, two strict-ISO compile traps, and a stop button that hung only on Linux because of how process kill behaves on POSIX. Testing on one platform had simply been unable to see any of them.

The architecture, in depth More articles