httpx.zig is a modern, high-performance HTTP library for Zig, providing everything needed to build fast and reliable networked applications, including HTTP clients, servers, APIs, web services, reverse proxies, and full-featured websites.
Related Zig projects:
- For API framework support, check out api.zig.
- For web framework support, check out zix.
- For logging support, check out logly.zig.
- For data validation and serialization support, check out zigantic.
⭐ If you build with httpx.zig, make sure to give it a star. ⭐
Note
Project maturity: This project aims to be production-ready and is actively maintained. It is still a new project and not yet widely adopted. Feel free to use it in your projects.
Custom HTTP/2 & HTTP/3 implementation: Zig's standard library does not provide HTTP/2, HTTP/3, or QUIC support. httpx.zig implements these protocols entirely from scratch, including:
- HPACK header compression (RFC 7541) for HTTP/2
- HTTP/2 high-level client and server runtime paths (preface/settings/headers/data flow)
- HTTP/2 stream multiplexing and flow control (RFC 7540)
- QPACK header compression (RFC 9204) for HTTP/3
- QUIC transport framing (RFC 9000) for HTTP/3
- HTTP/3 high-level client and server runtime paths over UDP + QUIC/HTTP3/QPACK primitives
- Interop note: strict TLS-in-QUIC server negotiation expectations may vary by endpoint deployment
Features (click to expand)
| Feature | Description | Documentation |
|---|---|---|
| Protocol Support | Full runtime support for HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3 in high-level client/server APIs, plus low-level protocol primitives. | https://muhammad-fiaz.github.io/httpx.zig/api/protocol |
| Header Compression | HPACK (RFC 7541) for HTTP/2 and QPACK (RFC 9204) for HTTP/3. | https://muhammad-fiaz.github.io/httpx.zig/guide/http2 |
| Stream Multiplexing | HTTP/2 stream state machine with flow control and priority handling. | https://muhammad-fiaz.github.io/httpx.zig/api/protocol |
| Connection Pooling | Automatic reuse of TCP connections with keep-alive and health checking. | https://muhammad-fiaz.github.io/httpx.zig/guide/pooling |
| Pool Introspection | Built-in connection pool stats and per-host connection counts. | https://muhammad-fiaz.github.io/httpx.zig/api/pool |
| Pattern-based Routing | Intuitive server routing with dynamic path parameters and groups. | https://muhammad-fiaz.github.io/httpx.zig/guide/routing |
| Port Conflict Handling | Explicit startup strategy to fail fast or auto-increment to the next free port. | https://muhammad-fiaz.github.io/httpx.zig/api/server |
| Middleware Stack | Built-in middleware for CORS, Logging, Rate Limiting, customized Auth, and more. | https://muhammad-fiaz.github.io/httpx.zig/guide/middleware |
| Pre-Route and Global Handlers | preRoute(...) hooks and global(...) fallback handlers for complete request lifecycle control. |
https://muhammad-fiaz.github.io/httpx.zig/api/server |
| Unified Any-Method Routing | any(path, handler) to register all standard HTTP methods on one endpoint. |
https://muhammad-fiaz.github.io/httpx.zig/api/server |
| Concurrency | Parallel request patterns (race, all, any) and async task execution. |
https://muhammad-fiaz.github.io/httpx.zig/guide/concurrency |
| Socket APIs | Cross-platform TCP/UDP socket helpers, listener wrappers, and TLS stream adapters. | https://muhammad-fiaz.github.io/httpx.zig/api/net |
| Proxy Support | Client-side HTTP forward proxy routing, SOCKS5h tunneling, and server-side reverse proxy middleware. | https://muhammad-fiaz.github.io/httpx.zig/examples/proxy-example |
| Interceptors | Global hooks to modify requests and responses (e.g., Auth injection). | https://muhammad-fiaz.github.io/httpx.zig/guide/interceptors |
| Logging Hooks | Server log callbacks plus logger middleware customization for structured output. | https://muhammad-fiaz.github.io/httpx.zig/api/middleware |
| Smart Retries | Configurable retry policies with exponential backoff. | https://muhammad-fiaz.github.io/httpx.zig/api/client |
| Config Builder Helpers | Chainable optional customization helpers for ClientConfig and RequestOptions (defaults remain implicit). |
https://muhammad-fiaz.github.io/httpx.zig/api/client |
| JSON and HTML | Helpers for easy JSON serialization and HTML response generation. | https://muhammad-fiaz.github.io/httpx.zig/api/core |
| Core Convenience APIs | Request query-param helpers and response constructors for redirect/text/json. | https://muhammad-fiaz.github.io/httpx.zig/api/core |
| TLS/SSL | Secure connections via TLS 1.3 support. | https://muhammad-fiaz.github.io/httpx.zig/api/tls |
| Static Files | Efficient static file serving capabilities. | https://muhammad-fiaz.github.io/httpx.zig/api/server |
| Streaming and Realtime | Chunked transfer responses with optional trailers and SSE response helpers. | https://muhammad-fiaz.github.io/httpx.zig/api/server |
| Cookie APIs | First-class request/response cookie helpers for both client and server contexts. | https://muhammad-fiaz.github.io/httpx.zig/api/server |
| Security | Security headers (Helmet) and safe defaults. | https://muhammad-fiaz.github.io/httpx.zig/api/middleware |
| No External Dependencies | Pure Zig implementation for maximum portability and ease of build. | https://muhammad-fiaz.github.io/httpx.zig/guide/installation |
| Shared Common Helpers | Reusable query/cookie helpers plus MIME resolution with explicit fallback and external mapping support. | https://muhammad-fiaz.github.io/httpx.zig/api/utils |
| WebSockets | RFC 6455 upgrade checks, handshake accept key computations, and frame encoding/decoding. | https://muhammad-fiaz.github.io/httpx.zig/examples/websocket-example |
| Multipart Form Data | RFC 2046 multipart body builder and parser for text fields and file uploads. | https://muhammad-fiaz.github.io/httpx.zig/examples/multipart-example |
| Session Management | TTL-based secure in-memory session store and cookie integration. | https://muhammad-fiaz.github.io/httpx.zig/examples/session-example |
| Observability & Metrics | Real-time traffic counters, per-class status tracking, and latency measuring. | https://muhammad-fiaz.github.io/httpx.zig/examples/metrics-example |
| Unix Domain Sockets | High-performance client-server IPC over AF_UNIX sockets. | https://muhammad-fiaz.github.io/httpx.zig/examples/unix-socket-example |
| Health Checks | Built-in liveness and readiness probe middlewares for deployments. | https://muhammad-fiaz.github.io/httpx.zig/examples/health-check-example |
Prerequisites and Supported Platforms (click to expand)
Before using httpx.zig, ensure you have the following:
| Requirement | Version | Notes |
|---|---|---|
| Zig | 0.16.0+ | Download from ziglang.org |
| Operating System | Windows 10+, Linux, macOS | Cross-platform networking support |
httpx.zig is validated on these architectures:
| Platform | x86_64 (64-bit) | aarch64 (ARM64) | x86 (32-bit) |
|---|---|---|---|
| Linux | Yes | Yes | Yes |
| Windows | Yes | Yes | Yes |
| macOS | Yes | Yes (Apple Silicon) | No |
Zig makes cross-compilation easy. Build for any target from any host:
# Build for Linux ARM64 from Windows
zig build -Dtarget=aarch64-linux
# Build for Windows from Linux
zig build -Dtarget=x86_64-windows
# Build for macOS Apple Silicon from Linux
zig build -Dtarget=aarch64-macos
# Build for 32-bit Windows
zig build -Dtarget=x86-windowsLatest Release (v0.1.1)
zig fetch --save https://github.com/muhammad-fiaz/httpx.zig/archive/refs/tags/0.1.1.tar.gzPrevious Stable Release (v0.1.0)
zig fetch --save https://github.com/muhammad-fiaz/httpx.zig/archive/refs/tags/0.1.0.tar.gzWarning
Zig 0.15 is deprecated and supported only by v0.0.7. New projects should use Zig 0.16.0+ with httpx.zig v0.1.1.
Use the latest development version from the main branch.
zig fetch --save git+https://github.com/muhammad-fiaz/httpx.zig.gitAdd the dependency to your build.zig.zon file.
.dependencies = .{
.httpx = .{
.url = "https://github.com/muhammad-fiaz/httpx.zig/archive/refs/tags/0.1.1.tar.gz",
.hash = "...", // Run `zig fetch --save <url>` to generate the hash.
},
},Clone the repository locally.
git clone https://github.com/muhammad-fiaz/httpx.zig.git
cd httpx.zig
zig buildTo use a local checkout from another project, add a path dependency to your build.zig.zon:
.dependencies = .{
.httpx = .{
.path = "../httpx.zig",
},
},After adding the dependency, import the module in your build.zig:
const httpx_dep = b.dependency("httpx", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("httpx", httpx_dep.module("httpx"));const std = @import("std");
const httpx = @import("httpx");
pub fn main() !void {
var gpa: std.heap.DebugAllocator(.{}) = .init;
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Create client with implicit defaults.
// Use explicit ClientConfig overrides only when you need to change defaults.
var client = httpx.Client.initForBaseUrl(allocator, "https://httpbin.org");
defer client.deinit();
// Simple GET request (request defaults are implicit)
var response = try client.get("/get", .{});
defer response.deinit();
if (response.ok()) {
std.debug.print("Response: {s}\n", .{response.text() orelse ""});
}
// POST with JSON
var post_response = try client.post(
"/post",
.{ .json = "{\"name\": \"John\"}" },
);
defer post_response.deinit();
// Cookie jar helpers
try client.setCookie("session", "abc123");
_ = client.getCookie("session");
// Pool stats/maintenance helpers (optional)
client.cleanupIdleConnections();
const pool_stats = client.poolStats();
_ = pool_stats;
}// Top-level aliases for concise client code.
// Allocator is implicit by default.
var response = try httpx.fetch("https://httpbin.org/get");
defer response.deinit();
// Defaults are implicit; pass .{} for default request options.
var by_method = try httpx.send(.GET, "https://httpbin.org/headers", .{});
defer by_method.deinit();
// Additional aliases
var del_res = try httpx.delete("https://httpbin.org/delete", .{});
defer del_res.deinit();
var opts_res = try httpx.opts("https://httpbin.org/get", .{});
defer opts_res.deinit();
// Optional explicit override (only when needed)
var timed = try httpx.sendWithAllocator(allocator, .GET, "https://httpbin.org/headers", .{ .timeout_ms = 10_000 });
defer timed.deinit();// Network lifecycle (optional explicit init/deinit)
try httpx.netInit();
defer httpx.netDeinit();
// Address helpers
const one = try httpx.resolveAddress("example.com", 443);
_ = one;
const parsed = try httpx.parseHostAndPort("localhost:8080", 80);
_ = parsed;
const final_addr = try httpx.parseAndResolveAddress("127.0.0.1:9000", 80);
_ = final_addr;
const is_ip = httpx.isIpAddress("::1");
_ = is_ip;const specs = [_]httpx.RequestSpec{
.{ .method = .GET, .url = "https://httpbin.org/get", .timeout_ms = 5_000 },
.{ .method = .GET, .url = "https://httpbin.org/headers", .version = .HTTP_2 },
};
var client_for_concurrency = httpx.Client.init(allocator);
defer client_for_concurrency.deinit();
var all_results = try httpx.all(allocator, &client_for_concurrency, &specs, .{});
defer {
for (all_results) |*r| r.deinit();
allocator.free(all_results);
}
const ok_count = httpx.successfulCount(all_results);
const err_count = httpx.errorCount(all_results);
_ = ok_count;
_ = err_count;
var first_ok = try httpx.first(allocator, &client_for_concurrency, &specs, .{});
if (first_ok) |*resp| resp.deinit();const std = @import("std");
const httpx = @import("httpx");
fn helloHandler(ctx: *httpx.Context) anyerror!httpx.Response {
return ctx.json(.{ .message = "Hello, World!" });
}
fn htmlHandler(ctx: *httpx.Context) anyerror!httpx.Response {
return ctx.html("<h1>Hello from httpx.zig!</h1>");
}
pub fn main() !void {
var gpa: std.heap.DebugAllocator(.{}) = .init;
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var server = httpx.Server.initWithConfig(allocator, .{
.host = "127.0.0.1",
.port = 8080,
.port_conflict = .increment,
.max_port_tries = 32,
});
defer server.deinit();
// Add middleware
try server.use(httpx.logger());
try server.use(httpx.cors(.{}));
// Register routes
try server.get("/", helloHandler);
try server.get("/page", htmlHandler);
// Start server
try server.listen();
// Effective port after startup (useful when port_conflict = .increment)
std.debug.print("Listening on {d}\n", .{server.listeningPort()});
}var server = httpx.Server.initWithConfig(allocator, .{
.host = "127.0.0.1",
.port = 8080,
.port_conflict = .increment, // try 8081, 8082, ... when 8080 is occupied
.max_port_tries = 32,
});
defer server.deinit();
try server.listen();port_conflict = .fail: fail immediately if the configured port cannot be bound.port_conflict = .increment: retry subsequent ports until success ormax_port_triesis exhausted.server.listeningPort(): returns the effective bound port.
The examples/ directory contains comprehensive, runnable examples demonstrating all features of httpx.zig:
- Client: Basic GET requests, POST with JSON, custom headers, connection pooling, proxy usage, request interceptors, and cookies.
- Server: Pattern-based routing, middleware configurations, static file serving, and multi-page web applications.
- Protocols: Multiplexed HTTP/2 client/server runtime and UDP-based HTTP/3 client/server runtime.
- Advanced Capabilities: RFC 6455 WebSockets, multipart form data building/parsing, session management, metrics dashboards with external callback event handlers, Unix domain socket IPC, and health/readiness probes.
To run any example:
zig build run-<example_name>
# e.g., zig build run-simple_get
# e.g., zig build run-websocket_exampleValidate host functionality and cross-target compatibility with these commands:
# Host runtime validation
zig build test
zig build run-all-examples
# Cross-target library compile validation
zig build build-all-targetsTo validate Linux runtime behavior (not just compilation), run Linux-target artifacts from a Linux shell (or WSL):
# Build Linux test/example artifacts
zig build test -Dtarget=x86_64-linux
zig build example-tcp_local -Dtarget=x86_64-linux
# Run on Linux/WSL
./zig-out/bin/test
./zig-out/bin/tcp_localIf a remote endpoint appears to stall, set a per-request timeout and print errors explicitly:
var response = client.get(url, .{ .timeout_ms = 10_000 }) catch |err| {
std.debug.print("request failed: {s}\n", .{@errorName(err)});
return;
};
defer response.deinit();For explicit cross-target test and example compilation, pass -Dtarget=...:
# Example: compile tests for 32-bit Windows
zig build test -Dtarget=x86-windows
# Example: compile an example for macOS ARM64
zig build example-tcp_local -Dtarget=aarch64-macosNote: this project exposes
build-all-targetsas a build step. Usezig build build-all-targets.
Run benchmarks:
zig build benchNote
Benchmark results will vary based on hardware and network conditions. The benchmark suite reports multiple rounds with min/avg/max and throughput to improve result quality.
Benchmark target: x86_64-windows, ReleaseFast.
| Benchmark | Avg (ns/op) | Throughput (ops/sec) |
|---|---|---|
| headers_parse | 17143.40 | 58331 |
| uri_parse | 30.54 | 32742548 |
| status_lookup | 0.87 | 1153375931 |
| method_lookup | 14.33 | 69779969 |
| base64_encode | 5740.49 | 174201 |
| base64_decode | 5647.98 | 177054 |
| json_builder | 5886.02 | 169894 |
| request_build | 28003.02 | 35710 |
| response_builders | 27856.15 | 35898 |
| executor_run_all | 178.57 | 5599956 |
| proxy_request_build | 46943.72 | 21302 |
| h2_frame_header | 0.96 | 1041362935 |
| h3_varint_encode | 0.97 | 1025960914 |
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
zig build test - Submit a pull request
MIT License - see LICENSE for details.
