https://github.com/lalinsky/zio
Async I/O framework for Zig
https://github.com/lalinsky/zio
async coroutines epoll fibers green-threads io io-uring iocp kqueue networking poll zig zig-package
Last synced: 1 day ago
JSON representation
Async I/O framework for Zig
- Host: GitHub
- URL: https://github.com/lalinsky/zio
- Owner: lalinsky
- License: other
- Created: 2025-09-16T12:12:46.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2026-05-24T20:39:55.000Z (8 days ago)
- Last Synced: 2026-05-24T22:23:11.278Z (8 days ago)
- Topics: async, coroutines, epoll, fibers, green-threads, io, io-uring, iocp, kqueue, networking, poll, zig, zig-package
- Language: Zig
- Homepage: https://lalinsky.github.io/zio/
- Size: 3.83 MB
- Stars: 493
- Watchers: 1
- Forks: 22
- Open Issues: 19
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# ZIO - Async I/O framework for Zig
[](https://github.com/lalinsky/zio/actions/workflows/test.yml)
[](LICENSE)
[](https://ziglang.org/download/)
[](https://lalinsky.github.io/zio/)
The project consists of a few high-level components:
- Runtime for executing stackful coroutines (fibers, green threads) on one or more CPU threads.
- Asynchronous I/O layer that makes it look like operations are blocking for easy state management, but using event-driven OS APIs under the hood.
- Synchronization primitives that cooperate with this runtime.
- Full implementation of the [`std.Io`] interface, so that you can use any Zig 0.16+ networking library.
- Seamless integration with standard library interfaces, like [`std.Io.Reader`] and [`std.Io.Writer`].
It's similar to [goroutines] in Go, but with the pros and cons of being implemented in a language with manual memory management and without compiler support.
> The main branch is for Zig 0.16 . For Zig master (0.17+), use the [`zig-0.17`](https://github.com/lalinsky/zio/tree/zig-0.17) branch.
[`std.Io`]: https://ziglang.org/documentation/0.16.0/std/#std.Io
[`std.Io.Reader`]: https://ziglang.org/documentation/0.16.0/std/#std.Io.Reader
[`std.Io.Writer`]: https://ziglang.org/documentation/0.16.0/std/#std.Io.Writer
[goroutines]: https://en.wikipedia.org/wiki/Go_(programming_language)#Concurrency
## Features
- Support for Linux (`io_uring`, `epoll`), Windows (`iocp`), macOS (`kqueue`), most BSDs (`kqueue`), and many other systems (`poll`).
- User-mode coroutine context switching for `x86_64`, `aarch64`, `arm`, `thumb`, `riscv32`, `riscv64`, `loongarch64` and `powerpc64` architectures.
- Growable stacks for the coroutines implemented by auto-extending virtual memory reservations.
- Single-threaded or multi-threaded coroutine scheduler.
- Fully asynchronous network I/O on all systems. Supports TCP, UDP, Unix sockets, raw IP sockets, etc.
- Fully asynchronous file I/O on Linux, partially asynchronous (read/write) on Windows. Using blocking syscalls in a thread pool on other systems.
- Fully asynchronous DNS resolver on Linux, Windows and macOS. Using `getaddrinfo` in a thread pool on other systems.
- Safe cancelation support for all operations.
- Structured concurrency using task groups.
- Synchronization primitives, including more advanced ones, like channels.
- Low-level event loop access for integrating with existing C libraries.
## Installation
1) Add zio as a dependency in your `build.zig.zon`:
```bash
zig fetch --save "git+https://github.com/lalinsky/zio#v0.13.0"
```
2) In your `build.zig`, add the `zio` module as a dependency to your program:
```zig
const zio = b.dependency("zio", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zio", zio.module("zio"));
```
## Usage
There are two main ways to use zio: the native API and the standard library's [`std.Io`] interface.
For most cases, prefer the `std.Io` interface, especially if you are writing a library.
The native API is more direct and has more features, but it ties you to the zio runtime.
A minimal TCP echo server, using zio's native API:
```zig
const std = @import("std");
const zio = @import("zio");
fn handleClient(stream: zio.net.Stream) !void {
defer stream.close();
var read_buffer: [1024]u8 = undefined;
var reader = stream.reader(&read_buffer);
var write_buffer: [1024]u8 = undefined;
var writer = stream.writer(&write_buffer);
while (true) {
const line = reader.interface.takeDelimiterInclusive('\n') catch |err| switch (err) {
error.EndOfStream => break,
else => return err,
};
try writer.interface.writeAll(line);
try writer.interface.flush();
}
}
pub fn main() !void {
const rt = try zio.Runtime.init(std.heap.smp_allocator, .{});
defer rt.deinit();
const addr = try zio.net.IpAddress.parseIp4("127.0.0.1", 8080);
const server = try addr.listen(.{});
defer server.close();
var group: zio.Group = .init;
defer group.cancel();
while (true) {
const stream = try server.accept(.{});
errdefer stream.close();
try group.spawn(handleClient, .{stream});
}
}
```
The same server written against the standard library's [`std.Io`] interface:
```zig
const std = @import("std");
const zio = @import("zio");
const Io = std.Io;
fn handleClient(io: Io, stream: Io.net.Stream) Io.Cancelable!void {
defer stream.close(io);
var read_buffer: [1024]u8 = undefined;
var reader = stream.reader(io, &read_buffer);
var write_buffer: [1024]u8 = undefined;
var writer = stream.writer(io, &write_buffer);
while (true) {
const line = reader.interface.takeDelimiterInclusive('\n') catch |err| switch (err) {
error.EndOfStream => break,
error.ReadFailed => return if (reader.err.? == error.Canceled) error.Canceled else {},
else => return,
};
writer.interface.writeAll(line) catch return if (writer.err.? == error.Canceled) error.Canceled else {};
writer.interface.flush() catch return if (writer.err.? == error.Canceled) error.Canceled else {};
}
}
pub fn main() !void {
const rt = try zio.Runtime.init(std.heap.smp_allocator, .{});
defer rt.deinit();
const io = rt.io();
const addr = try Io.net.IpAddress.parseIp4("127.0.0.1", 8080);
var server = try addr.listen(io, .{});
defer server.deinit(io);
var group: Io.Group = .init;
defer group.cancel(io);
while (true) {
const stream = try server.accept(io);
errdefer stream.close(io);
try group.concurrent(io, handleClient, .{ io, stream });
}
}
```
See `examples/*.zig` for more examples.
## Building
```bash
# Run tests
zig build test
# Build examples
zig build examples
```
## Contributing
See [DEVELOPMENT.md](DEVELOPMENT.md).
## License
This project is licensed under the [MIT license].
[MIT license]: https://github.com/lalinsky/zio/blob/main/LICENSE