| Documentation | DeepWiki | Coverage | Build Status |
|---|---|---|---|
| zerofmk.in |
One binary. No GC. Build config-driven microservices in Zig.
Zero is a batteries-included web framework for Zig that wires REST, SQL, NoSQL, cache, pub/sub, auth, GraphQL, Protobuf, search, metrics and tracing into a single static binary and configured almost entirely through .env.
- Zero boilerplate — databases, queues, auth and observability plug in with no glue code.
- One static binary — ~16–65 MiB RSS, no runtime, ships anywhere (including Kubernetes).
- Observable by default — structured JSON logs, Prometheus metrics, distributed tracing and health endpoints from the first request.
- Fast and small — tens of thousands of requests/sec at ~50 MiB RSS, no GC pauses, no JIT warm-up.
Drop this in src/main.zig, add a configs/.env, and you have a JSON API with
structured logs and /metrics live:
const std = @import("std");
const zero = @import("zero");
const utils = zero.utils;
pub const std_options: std.Options = .{ .logFn = zero.logger.custom };
pub fn main(init: std.process.Init) !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const app = try zero.App.new(arena.allocator(), init.io, init.environ_map);
try app.get("/json", jsonResponse);
try app.run();
}
fn jsonResponse(ctx: *zero.Context) !void {
try ctx.json(.{ .msg = "hello zero!" });
}zig fetch --save https://github.com/im-ng/zero/archive/refs/heads/main.zip
mkdir -p configs && printf 'APP_NAME=hello\nHTTP_PORT=8080\n' > configs/.env
zig build run
curl localhost:8080/json # => {"msg":"hello zero!"}That's the whole app. Everything else - Postgres, Redis, Kafka, auth, metrics, is opt-in through configuration.
Full walkthrough in Hello Zero and Getting Started.
If you want Go's ergonomics without its runtime, or Node's speed without its footprint, Zero gives you a strongly-opinionated Zig framework: explicit memory, a single binary, and the microservice building blocks you'd otherwise wire together by hand.
Start with Getting Started or jump straight to the Examples.
| Category | Status | Details |
|---|---|---|
| REST / CRUD | ✅ | Standard REST endpoints out of the box; AutoCRUD for struct models |
| Configuration | ✅ | .env with per-environment overrides (/configuration) |
| Logging | ✅ | Structured, UTC/local timestamps (/logging) |
| Metrics | ✅ | App, HTTP, SQL, KV + process/memory stats (/observability) |
| Tracing | ✅ | TraceID middleware, request-level tracing (/x-ray) |
| Auth | ✅ | Basic, API Key, OAuth 2.0 (/authentication) |
| CORS / Panic Recovery | ✅ | Configurable CORS, automatic panic recovery |
| Databases | ✅ | PostgreSQL, SQLite, Redis, DuckDB, InfluxDB, Solr, Cassandra (/sqlite, /duckdb, /cassandra, /influxdb, /solr) |
| Pub/Sub | ✅ | MQTT, NATS, Kafka (librdkafka), Redis (/pubsub) |
| Migrations | ✅ | DB migrations + seed on startup (/migrations) |
| HTTP Client | ✅ | Register multiple external services with auth + circuit breakers (/http-service) |
| Cron Jobs | ✅ | * * * * * + second-level + range support (/cronz) |
| WebSockets | ✅ | Built-in WebSocket support (/websocket) |
| Static Files | ✅ | Serve static assets + Swagger UI (/swagger) |
| Health Checks | ✅ | Liveness + status endpoints |
| GraphQL | ✅ | Schema-less resolvers over HTTP (/graphql) |
| Protobuf | ✅ | proto3 codegen + bind/decode & encode over HTTP (/protobuf) |
See feature parity for the full roadmap.
Recent additions (full detail on zerofmk.in):
-
Zig 0.16 +
std.Ioinjection —App.new(allocator, io, em)threads the process I/O reactor throughcontainer/Context; tests are consolidated at each file's end. See Migrating to 0.16. -
DuckDB in-process OLAP — register an embedded SQL engine with
app.addDuckDB(":memory:"), no external service. See DuckDB. -
AutoCRUD for DuckDB —
app.addRestHandlersnow targets DuckDB too. See Auto CRUD. -
CLI Application Mode — build one-shot jobs or long-running migrations with
App.newCmd+app.SubCommand, no HTTP server. See CLI Mode. -
Kubernetes deployment — sample image build + manifests. See Kubernetes and Container.
-
New data sources — Cassandra, InfluxDB and Solr join the supported backends. See /cassandra, /influxdb, /solr.
-
Bootstrap arena — Pre-allocated memory for framework bootstrap (bounded RSS). See Architecture.
-
Outbound rate limiting & REST handlers — per-service rate limits and struct-model REST handlers for external services. See Rate Limiter and REST Handler.
-
Resilience — circuit breakers, request timeouts/bulkheads, and pub/sub reconnect + dead-letter. See Resilience.
-
Observability — distributed tracing and structured metrics/tracing wired in from the first request. See Observability.
-
Benchmarks in CI — reproducible throughput/latency/RSS runs. See Benchmark.
Every feature ships with a runnable example under examples/. Pick one and zig build run from its directory.
Basics
zero-basic— JSON / text routes, DB read, key-value, local file store.zero-stream— live host/cpu/status metrics streamed over WebSocket + cron.zero-websocket— minimal WebSocket handler.zero-todo-htmx— HTMX UI backed by AutoCRUD.zero-cli— CLI mode: one-shot jobs / migrations, no HTTP server.zero-cronz— scheduled cron jobs (* * * * * *).
Data & Stores
zero-sqlite— SQLite CRUD.zero-duckdb— in-process DuckDB OLAP + CRUD.zero-nosql— Cassandra / NoSQL key-value CRUD.zero-redis— Redis caching.zero-timeseries— InfluxDB time-series write/query.zero-search— Solr index + search.zero-filestore— local file upload/download.zero-s3— S3-compatible object store.
Messaging
zero-mqtt-publisher/zero-mqtt-subscriber— MQTT publish/subscribe.zero-kafka-publisher/zero-kafka-subscriber— Kafka publish/subscribe.zero-nats-publisher/zero-nats-subscriber— NATS publish/subscribe.
Auth & API
zero-auth— Basic / API-Key / OAuth2 auth handlers.zero-service-client— outbound HTTP service with auth + circuit breaker.
GraphQL & Protobuf
zero-graphql— GraphQL resolvers.zero-proto— Protobuf bind/decode over HTTP + migration.
Migrations & Deployment
zero-migration— DB migration + seed.zero-autocrud— one-line AutoCRUD for aUserresource.
The full, versioned documentation lives at zerofmk.in (Zig 0.16 is the live locale; 0.15.2 is frozen under /0.15.2/). You can also ask the repo anything via DeepWiki. Per-feature deep dives:
- Concepts: Architecture, Context, Interface, Configuration
- Data: SQLite, DuckDB, Cassandra, InfluxDB, Solr, KV Store, File Store, Migrations
- Networking: HTTP Service, Pub/Sub, Kafka, NATS, Rate Limiter, REST Handler
- App concerns: Auth, Resilience, Observability, x-ray, Caching, Logging, CLI, Cron, GraphQL, Protobuf, WebSocket, Swagger, Testing, Benchmark
Zero is configured through configs/.env with per-environment overrides
(configs/.dev.env, etc.). A minimal file:
APP_NAME=my-app
HTTP_PORT=8080
# PostgreSQL
DB_DIALECT=postgres
DB_HOST=localhost
DB_USER=user1
DB_PASSWORD=password1
DB_NAME=mydb
DB_PORT=5432
# Auth
AUTH_MODE=BasicThe complete list of keys (Redis, DuckDB, InfluxDB, Solr, Cassandra, Kafka, MQTT, TLS, metrics, logging, rate limiting, RBAC, …) is in Configuration.
Resilience is configured, not coded. Request timeouts/bulkheads, datasource circuit breakers, pub/sub auto-reconnect with dead-letter, and structured logging are all on by default or via env. For outbound services you can also set limits explicitly:
var svc_opts: zero.client.ServiceOptions = .{};
svc_opts.circuitBreaker = .{ .failure_threshold = 5, .cooldown_ms = 30_000 };
try app.addHttpService("auth-service", app.config.get("SERVICE_URL"), svc_opts);See Resilience for timeouts, bulkheads and DLQ behavior.
Prometheus metrics are exposed at /metrics and a health endpoint at /.well-known/health (liveness/status). Distributed tracing via TraceID is attached to every request.
curl localhost:8080/metrics # http_requests_total, app_sql_response, ...
curl localhost:8080/.well-known/healthSee Observability
Attach a datastore with one call; ctx.SQL, ctx.KV, ctx.FileStore light up automatically.
// In-process OLAP SQL — no external service required.
try app.addDuckDB(":memory:");
// or a relational backend:
// try app.addSQL(...); try app.addSQLite(...); try app.addNoSQL(...);
fn listUsers(ctx: *zero.Context) !void {
const users = try ctx.SQL.queryRows(ctx, User, "SELECT id, name FROM users", .{});
try ctx.json(.{ .data = users });
}SQL, NoSQL, cache, pub/sub and file stores:
/sqlite, /duckdb, /cassandra, /influxdb, /solr, /kv-store, /file-store.
One line wires list / get / create / update / delete for a struct model:
const User = struct { id: i64, name: []const u8, email: []const u8 };
try app.addRestHandlers(User, .{ .resource = "users" });
// GET/POST/PUT/DELETE /users, /users/:idSee Auto CRUD.
Inbound auth is config-driven (AUTH_MODE = Basic | APIKey | OAuth). Handlers read the verified claims from the context:
try app.get("/basic", basicResponse);
fn basicResponse(ctx: *zero.Context) !void {
const claims = try ctx.getUsername();
try ctx.json(claims.?);
}See Authentication.
Subscribe to MQTT, NATS or Kafka; the same handler shape works for all:
try app.addKafkaSubscription("topic", onMessage);
// MQTT: try app.addSubscription("topic", onMessage);
// NATS: try app.addPubSubSubscription("topic", onMessage);
fn onMessage(ctx: *zero.Context) !void {
// ctx.message holds the payload
}Schema-less resolvers over HTTP (POST/GET). Struct fields map to types; function fields are invoked as resolvers:
try app.addGraphQL(query_root, mutation_root);See GraphQL.
Generate structs from .proto and bind/decode over HTTP:
const msg = try ctx.bindProto(MyProtoMsg); // POST body -> struct
try ctx.protobuf(msg); // struct -> response bytesSee Protobuf.
Build one-shot commands or long-running migrations without an HTTP server:
pub fn main(init: std.process.Init) !void {
const app = try zero.App.newCmd(allocator, init.io, init.environ_map);
try app.SubCommand("migrate", runMigration, .{ .description = "run migrations" });
try app.runCmd(init.minimal.args);
}See CLI Mode.
Handlers are plain functions over *Context, so they're trivial to unit test. The framework's own suite runs 130+ tests with coverage; the harness is documented in Testing:
test "health responds ok" {
const ctx = try Context.initCli(allocator, container);
try ctx.json(.{ .ok = true });
}The bundled benchmark harness drives a concurrency ramp and reports throughput, latency percentiles and per-level RSS. CI runs it for regression. Reproduce in Benchmark.
Build a single static binary and deploy anywhere. Sample image + manifests in Kubernetes and Container:
FROM alpine:latest
COPY zig-out/bin/app /app
EXPOSE 8080
ENTRYPOINT ["/app"]| Branch | Version |
|---|---|
| main | 0.16.0 (experimental) |
| stable-0.15.2 | 0.15.2 |
For stable work prefer the stable-0.15.2 branch; main tracks the 0.16 experimental baseline (including the std.Io injection described above). See Migrating to 0.16.
src/ framework source (App, Context, container, datasource, pubsub, …)
examples/ 26 runnable example apps
configs/.env per-environment configuration
static/ embedded swagger UI + framework assets
build.zig build wiring (test / integration / validation / bench)
-
Kafka requires the system
librdkafkadev package to be installed and linked weakly.apt install librdkafka-devbrew install librdkafka -
DuckDB needs
libduckdb.so/duckdb.hon the library path (see DuckDB). -
The
kafkabuild option is commented out; rdkafka is always linked. -
Auth modes:
Basic,APIKey,OAuth.
Apache — see LICENSE.
