zig build test -Doptimize=ReleaseSafe
zig build c-abi-test -Doptimize=ReleaseSafe
zig build bench -Doptimize=ReleaseFast
zig build run
zig build examples
zig build example -Dexample=01_minimal_spawnzig build also installs the static C library (libzigroutines/zigroutines.lib) and include/zigroutines.h.
zigroutines is a library for explicit stackful concurrency in Zig. It gives you a Go-shaped model (tasks, channels, select, cancellation, timers) with Zig’s philosophy: nothing global, nothing hidden, pay only for what you enable.
Unlike a "runtime baked into the language", you construct a Runtime, choose the scheduler policy, I/O backend, and metrics. Stacks are fixed 2 KiB (no growth, no per-task dial). No GC. No netpoller until you plug one in.
At a glance:
| Property | Value |
|---|---|
| Model | M:N stackful tasks on fixed 2 KiB stacks (no growth, no per-task size choice) + opt-in leaf (stackless run-to-completion) |
| Schedulers | FIFO · work-stealing · priority · 1 OS thread per task |
| CSP | Channel(T), rendezvous / buffered, multi-arm select (up to 32 arms per kind) |
| Cancellation | Cooperative, hierarchical CancelToken, Scope / Nursery |
| I/O | Plugin: none / poll / iocp / io_uring |
| Synchronization | Mutex (adaptive), Semaphore, RwLock, RateLimiter, Notify, Watch(T) — park the task, not the OS thread |
| Timers | Hierarchical wheel (256×1 ms) + heap overflow |
| Cost | Pay-for-what-you-use; stack pool + task freelist on; in-stack spawn args/result; channel createPooled for hot create |
-
Write top-down “sync-looking” code —
send/recv/sleep/yieldlook like ordinary calls; under the hood the task parks and yields the CPU to other fibers. No function coloring (async/awaitdoes not infect the call tree). -
Predictable resources — every fiber has a fixed 2 KiB stack (no size dial). Heavy buffers go on the heap. Stack pool on by default. Overflow policy is opt-in (
none/canary/guard); guard pages share a reserved arena so they do not cost 8 KiB committed + one VMA per task. -
Swap scheduling policy without changing the API — the same
spawnworks on FIFO (1 worker), work-stealing (many cores), priority, and thread-per-task. -
Go-style CSP — channels, rendezvous, backpressure policies (
block,drop_newest,drop_oldest,error_full),selectwith timeout and cancel. -
Structured concurrency —
Scope/Nurserywith deadline,cancel_on_leave,cancel_on_first_done, typedspawnResult+JoinHandle. -
Pluggable I/O — I/O off by default (the core stays quiet); when needed — poll / IOCP / io_uring, TCP/UDP helpers, bridge to
std.Io. -
Observability — optional atomic metrics, tracing hooks, preemption checkpoints.
-
Actors and C ABI —
Actor(Message)(mailbox = channel + loop), optional C surface.
| libxev | zigcoro / zio | zigroutines | |
|---|---|---|---|
| Primary job | Event loop / completions | Coroutines + some I/O | Full concurrency stack |
| Stackful sync style | No (callback / future) | Yes | Yes |
| Channels + multi-select | No | Partial / ad-hoc | First-class CSP |
| Pluggable scheduler policies | N/A | Limited | FIFO / WS / priority / 1:1 |
| Fixed stack + pool + guard | N/A | Varies | Explicit and default |
| Structured cancel / nursery | No | Limited | Scope + Nursery |
| Quiet netpoller by default | You wire it | Often coupled to the runtime | Off until you configure it |
| Go | C++20 / fiber libs | async Rust + Tokio | zigroutines | |
|---|---|---|---|---|
| DX | Excellent (go, chan, select) |
Assemble the pieces | async/await, Pin/Send |
Same shape, native Zig |
| Runtime | Hidden M:N | Zoo of executors | Multiple runtimes | Explicit Runtime |
| Stack | Grows (copy) | Stackless or 3rd-party fibers | Stackless state machines | Fixed only |
| GC | Yes, STW risk | No | No | No |
| Netpoller | Built-in, not optional | Whatever you build | Usually in the runtime | Off by default |
| Function coloring | No | co_await |
async everywhere |
No |
Go wins “ship a service in an afternoon.” zigroutines wins when you cannot accept GC, silent stack growth, or an immovable runtime. C++ can match the control if you are an expert and assemble the stack yourself. Tokio is world-class for Rust; on Zig, zigroutines keeps the mental model “task + stack + channel” without async coloring.
The Zig-library table above is a glance. 5.3 is why a nanosecond in 5.2 is not a product verdict: zigcoro, zio, and libxev are different machines, and a cell we lose is usually a constraint they do not have.
- One coherent surface — scheduler, I/O, cancel, CSP, stacks, metrics: policies you enable, not a hidden runtime.
- Honest to Zig — no process-global runtime, no GC, no silent growth; pay only for enabled features.
- Go-shaped DX — write top-down; park on channels/timers/I/O without rewriting the call tree.
- Measurable cost — fixed stacks, context saved on the fiber stack (not in the TCB), optional metrics/canary, explicit park/wake rules.
Package version: 1.0.0. Repository: Apanazar/zigroutines.
Pin a release (hash is filled by zig fetch --save):
zig fetch --save=zigroutines https://github.com/Apanazar/zigroutines/archive/refs/tags/v1.0.0.tar.gzOr from a local checkout:
zig fetch --save=zigroutines ./path/to/zigroutinesThen in build.zig.zon you will have something like:
.{
.name = .my_app,
.version = "0.0.1",
.dependencies = .{
.zigroutines = .{
.url = "https://github.com/Apanazar/zigroutines/archive/refs/tags/v1.0.0.tar.gz",
.hash = "…", // written by zig fetch --save
},
},
.paths = .{""},
}Wire the module in build.zig:
const zr_dep = b.dependency("zigroutines", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zigroutines", zr_dep.module("zigroutines"));const zr = @import("zigroutines");
var rt = try zr.Runtime.init(allocator, .{ .workers = 1 });
defer rt.deinit();
_ = try rt.spawn(.{}, myFn, .{});
try rt.run();- Architecture — layers, control flow, full entity/mechanism catalog with file locations
- Usage examples — runnable snippets (spawn, channels, select, nursery, C ABI)
- Tests and coverage — suite map, what is treated as a necessary case
- Benchmarks — Go/Rust/C++ and Zig-library comparisons, methodology
- Runtime configuration — full options cheat sheet
- Changelog — 1.0.0 release notes