Skip to content

Repository files navigation

Baz

Bounded Async Zap.

Website & documentation · API guide · 24 examples

A pure Zig successor to Zap, built in Zig 0.16.0 on bounded/http. It keeps Zap's typed App and endpoint ergonomics, with explicit memory ownership and simpler request data. Both Baz and its HTTP engine are implemented in Zig. Baz replaces Zap’s facil.io C foundation with bounded/http. The engine's GitHub Pages documentation explains its architecture, embedding API, and ownership model; the engine source is a separate repository.

Its foundation, bounded/http, takes inspiration from TigerStyle: set explicit limits, reserve resources up front, and check ownership invariants. Connections, buffers, queues, and workers have fixed capacities; request sizes, response sizes, and I/O deadlines have enforced limits. When capacity runs out, the engine applies backpressure or rejects work instead of growing without bounds. These guarantees cover the framework's resources; application code still owns its memory use and must cooperate with cancellation.

Native HTTP backends: Linux · io_uring, macOS · kqueue, Windows · IOCP. Baz uses these transports directly through bounded/http, alongside your application's caller-supplied std.Io.

The first implementation provides:

  • Streaming responses: write, flush, sleep, and write again inside one handler, through a standard std.Io.Writer. See the streaming guide and runnable example.
  • Mustache templates: parse once at startup, render typed data directly into reserved HTML response storage. See the guide and greeting form and user-card example. Verified natively on Linux, macOS, and Windows.
  • SSE and producer notifications: encode events into a standard writer, wake retained callbacks, and choose explicit queue and replay limits. SSE guide · complete job application · native and browser evidence.
  • Many waiting streams, few workers: typed continuations retain bounded state between flushes and timers, releasing the executor.
  • Cookies and redirects: borrowed token views, explicit session/persistent expiry, scoped deletion, and empty redirects. See the guide and local login/logout example.
  • Real App(Shared) instances, plain endpoint structs and one router.
  • Borrowed query and form text, ordered duplicates and explicit decoding into caller buffers. Values such as 001 and false, and names such as a[], keep their spelling.
  • Flat multipart parts: fields and files use one iterator, with optional filename metadata and borrowed bytes.
  • Bounded one-shot responses, JSON and copied headers; output capacity is secured before the handler runs.
  • Caller-supplied std.Io and standard memory readers/writers, on bounded/http's io_uring, kqueue, and IOCP transports. Blocking services use explicit fixed workers.

Baz is a separate framework package with a pinned external engine dependency. The package and public import are baz; the engine import is bounded_http. The engine remains independently usable as a standalone case study. Baz has its own GitHub repository and GitHub Pages site. The package boundary and roadmap record the dependency, upstream changes, and remaining work. See the repository record for branches, history, CI, and publication status.

Platform support

Linux, macOS, and native Windows x64 are supported. Baz adds native Windows support beyond Zap’s facil.io-based platform support. Both the framework and its bounded/http engine are written in Zig.

Platform Native HTTP backend
Linux io_uring
macOS kqueue
Windows x64 IOCP

All three platforms passed Debug and ReleaseSafe verification, the independent package consumer, all 14 App groups, all 20 ported-example groups, and all 14 streaming groups—including the runnable example—plus nine large-borrow groups. Windows also passed three native shard-handoff and console-shutdown cases. See the large-borrow and three-platform receipt for exact environments and evidence. Windows is supported within Baz’s overall experimental status; this is correctness coverage, not production qualification.

Try it

Watch a response arrive incrementally:

zig build run-streaming -Doptimize=ReleaseSafe -- --port 8080
# In another terminal; use curl.exe on Windows:
curl -N http://127.0.0.1:8080/

The handler sends three updates with pauses between them. Each stream uses one fixed application worker and bounded output storage. The HTTP I/O loop continues while the worker waits. Response size and request deadlines still apply; the guide explains cancellation and framing. Response helpers have explicit copying and borrowing paths; the copy contract describes their costs and lifetimes. borrowBody can serve a large immutable asset directly from retained memory, bounded by the total response limit rather than staging capacity. It selects the whole body; inserting a borrowed image between streaming writes is currently unsupported.

Use exact Zig 0.16.0 from .zig-version, with Python 3 installed:

zig build run-app -Doptimize=ReleaseSafe -- --port 8080

In another terminal (use curl.exe on Windows):

curl 'http://127.0.0.1:8080/hello?name=Hello%20Zig'
curl --data 'value=x+y%2Bz' http://127.0.0.1:8080/form
curl -F 'files[]=@.zig-version' http://127.0.0.1:8080/upload

Start with the API guide and compiled App example. There are 21 ports of Zap's examples, including endpoints, authentication, middleware, sessions, Mustache, JSON, query/form data and uploads:

zig build examples -Doptimize=ReleaseSafe
./zig-out/bin/hello --port 8080
zig build run-http_params -Doptimize=ReleaseSafe -- --port 8080

All examples use zli with Zig 0.16 std.process.Init for typed startup options and --help. Both --port 8080 and --port=8080 work. See the CLI guide.

Public middleware and typed request locals compose global and route authentication hooks with deterministic cleanup. The session example uses 32 reusable slots, fixed server expiry, and individual or all-device logout. Typed continuations let many waiting streams share a small worker pool: return flush, wait, or finish with bounded typed state.

Basic performance comparison with Zap

Native results from the initial App prototype at c152e59 on 2026-09-06, before package extraction. These compare the public App/Response API with its predecessor Zap, using the local Zig 0.16 port pinned at f6099ecec496c7ec623c5913baa5b6b5da2e883d.

Host Connections / client threads Baz prototype requests/s Zap requests/s App / Zap
macOS, Apple M3 Max 32 / 2 254,261 245,054 1.038×
Linux, Intel Core Ultra 7 258V 32 / 2 363,594 205,310 1.771×
macOS, Apple M3 Max 1 / 1 33,199 52,809 0.629×
Linux, Intel Core Ultra 7 258V 1 / 1 74,386 72,575 1.025×

These are medians of three alternating paired trials: one-second warmup, three-second measurement, 13-byte plaintext, keep-alive without pipelining, one server thread and 128 connection slots. Every benchmark and warmup used ReleaseSafe; Zig assertions stayed enabled. All 24 measured trials completed with zero reported wrk socket/non-2xx-or-3xx errors.

The 32-connection results show similar throughput on this Mac and higher App throughput on this Linux host; the one-connection baseline is lower for App on Mac. These short same-host loopback runs establish neither capacity nor latency, and do not isolate API overhead. Clients were unpinned and wrk revisions differ between hosts. Zap retained its original facil.io C flags, including -Os and -fno-sanitize=undefined. Exact bodies were checked before and after timing, not individually for every timed response. See the full protocol, ranges, source identities and raw receipts.

Status and documentation

This is an experimental first implementation. Runtime source at 86249ad passed native Linux, macOS, and Windows large-borrow, streaming, and regression gates. The large-borrow receipt identifies the exact sources and retains the raw results. The engine passed its own native gates separately. The package receipt records external-dependency verification and source identity. The prototype receipt preserves the earlier combined engine/framework gates.

Current deployment is IPv4 loopback, plain HTTP/1.1. TLS is out of scope. Mustache uses a pure Zig library with bounded rendering. WebSockets needs an engine upgrade lifecycle. Native Windows x64 now has its own CI gate, alongside Linux and macOS. An owned std.Io provider and its prototype remain deferred by user decision.

Framework storage is reserved at startup; borrowed input and output remain alive until their owners finish. Application services and the caller's I/O provider have their own resource responsibilities. Read the ownership contract before retaining slices or introducing asynchronous work.

License

Baz is MIT licensed. The adapted Zap examples retain their original copyright and license notice.

About

Baz — Bounded Async Zap. A modern Zig 0.16.0 web framework on bounded/http.

Resources

Stars

15 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages