A Zig client library for etcd, built on HTTP/2 (h2c) with nghttp2.
Work in progress — API will change.
- Unary gRPC calls —
Put,Range, and other request/response RPCs viagrpc.unaryCall - Server-streaming gRPC —
Watchviagrpc.openServerStream/GrpcStreamReader - WatchIterator — high-level watch API with automatic reconnect and revision tracking
- Protobuf — generated Zig bindings for etcd's protobuf types via zig-protobuf
- Zig 0.15.2
- A running etcd instance (h2c, no TLS)
zig build
const etcd = @import("etcd");
// Unary call (Put)
var conn: etcd.H2Connection = try .connect(allocator, "localhost", 2379);
defer conn.deinit();
try conn.performHandshake();
const resp = try etcd.grpc.unaryCall(allocator, &conn, "/etcdserverpb.KV/Put", req_bytes);
defer resp.deinit(allocator);
// Watch with automatic reconnect
var iter: etcd.WatchIterator = .init(allocator, "localhost", 2379, .{
.target = .{ .prefix = "my-prefix/" },
.start_revision = 0,
});
defer iter.deinit();
while (iter.next()) |resp| {
var r = resp;
defer r.deinit(allocator);
for (resp.events.items) |event| {
// handle event
}
}WatchIterator accepts a KeyRange:
| Variant | Description |
|---|---|
.single = "key" |
Watch a single key |
.prefix = "pfx/" |
Watch all keys with a prefix |
.range = .{ .start = "a", .end = "z" } |
Watch a half-open range [a, z) |
.all |
Watch the entire keyspace |
Start etcd, then:
zig build run
In another terminal:
etcdctl put hello world
etcdctl put hello universe
etcdctl del hello
zig build test
src/
root.zig — Library entry point and public exports
grpc.zig — gRPC framing (unary + server-streaming)
h2_connection.zig — HTTP/2 connection (nghttp2 wrapper)
watch.zig — WatchIterator, KeyRange, PrefixEnd
main.zig — Demo executable
proto/ — Generated protobuf bindings
proto/ — .proto source files