Low-latency HTTP/1.1 server primitives for Zig with comptime routing, typed captures, and composable middleware.
- 🧭 Comptime route table: define routes once with
zhttp.Server(.{ .routes = .{ ... } }). - 🧠 Typed request captures: decode headers, query params, and path params with
zhttp.parse.*. - 🪝 Flexible handlers: support no-arg, request-only, context-only, or context + request handlers.
- 🧱 Composable middleware: mix global and per-route middleware with compile-time
Needsmerging. - 📦 Built-in middleware: static files, CORS, logging, compression, timeout, ETag, request IDs, and security headers.
- 🏎 Tight hot path: direct request parsing and response writing for low-overhead HTTP/1.1 servers.
- 🧪 Runnable examples + benchmarks: example servers and a small benchmark harness live in-tree.
zig build examples
./zig-out/bin/zhttp-example-basic_server --port=8080
zig build examples-checkMinimal server:
const std = @import("std");
const zhttp = @import("zhttp");
fn hello(req: anytype) !zhttp.Res {
const name = req.queryParam(.name) orelse "world";
const body = try std.fmt.allocPrint(req.allocator(), "hello {s}\n", .{name});
return zhttp.Res.text(200, body);
}
pub fn main(init: std.process.Init) !void {
const App = zhttp.Server(.{
.routes = .{
zhttp.get("/hello", hello, .{
.query = struct {
name: zhttp.parse.Optional(zhttp.parse.String),
},
}),
},
});
const addr: std.Io.net.IpAddress = .{ .ip4 = std.Io.net.Ip4Address.loopback(8080) };
var server = try App.init(init.gpa, init.io, addr, {});
defer server.deinit();
try server.run();
}Add as a dependency:
zig fetch --save <git-or-tarball-url>build.zig:
const zhttp_dep = b.dependency("zhttp", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zhttp", zhttp_dep.module("zhttp"));zhttp.Server(.{ ... })accepts.Context,.middlewares,.routes,.config, and.error_handler.- Route helpers:
zhttp.get,post,put,delete,patch,head,options, andzhttp.route(...). - Route options:
.headers,.query,.params,.middlewares. - Header capture keys match case-insensitively, and
_in field names matches-in incoming headers. - If
.paramsis omitted, path params default to strings. - Typed request accessors include
req.header(...),req.queryParam(...),req.paramValue(...), andreq.middlewareData(...).
zhttp.middleware.Staticzhttp.middleware.Corszhttp.middleware.Loggerzhttp.middleware.Compressionzhttp.middleware.Timeoutzhttp.middleware.Etagzhttp.middleware.RequestIdzhttp.middleware.SecurityHeaders
See examples/builtin_middlewares.zig for the full built-in stack in one server.
examples/basic_server.zigexamples/middleware.zigexamples/builtin_middlewares.zigexamples/echo_body.zigexamples/fast_plaintext.zig
Benchmark support lives under benchmark/.
zig build bench -Doptimize=ReleaseFast -- --mode=zhttp --conns=1 --iters=200000 --warmup=10000
zig run benchmark/run_zhttp_external.zig
BENCH_BIN=./zig-out/bin/zhttp-bench zig run benchmark/run_faf.zig
zig run benchmark/run_compare.zigFor the full benchmark modes and notes, see benchmark/README.md.
zig build test
zig build examples
zig build examples-check
zig build bench-serverzhttp is intentionally focused on a small HTTP/1.1 server core.
- Request parsing covers HTTP/1.0 and HTTP/1.1.
- Responses are written as HTTP/1.1 with
Content-Length. - Keep-alive and HEAD response semantics are handled.
- Chunked responses are not implemented yet.