Zig is a systems programming language designed as a better C. It cross-compiles to 40+ targets out of the box, has no hidden control flow, no hidden allocations, and can directly import C headers.
Why Zig?
- Cross-compilation — target any OS/arch from any OS, built-in
- C interop — import C headers directly, no bindings
- No hidden allocations — you control every allocation
- Comptime — compile-time code execution (replaces macros/generics)
-
Drop-in C compiler —
zig ccreplaces gcc/clang with cross-compile
Install
# macOS
brew install zig
# Linux
snap install zig --classic
# Or download from ziglang.org
curl -L https://ziglang.org/download/0.13.0/zig-linux-x86_64-0.13.0.tar.xz | tar xJ
Hello World
// hello.zig
const std = @import("std");
pub fn main() void {
std.debug.print("Hello, {s}!\n", .{"World"});
}
zig build-exe hello.zig
./hello
# Cross compile to Linux ARM (from macOS!)
zig build-exe hello.zig -target aarch64-linux
# Cross compile to Windows
zig build-exe hello.zig -target x86_64-windows
HTTP Server (std.http)
const std = @import("std");
const net = std.net;
const http = std.http;
pub fn main() !void {
var server = http.Server.init(.{ .reuse_address = true });
defer server.deinit();
const address = net.Address.parseIp("0.0.0.0", 8080) catch unreachable;
try server.listen(address);
std.debug.print("Listening on :8080\n", .{});
while (true) {
var response = try server.accept();
defer response.deinit();
try response.headers.append("Content-Type", "application/json");
try response.do();
const body = \\
\\{"status": "ok", "message": "Hello from Zig!"}
;
_ = try response.write(body);
try response.finish();
}
}
Comptime (Compile-Time Execution)
// Generic data structure — computed at compile time
fn ArrayList(comptime T: type) type {
return struct {
items: []T,
capacity: usize,
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) @This() {
return .{
.items = &.{},
.capacity = 0,
.allocator = allocator,
};
}
pub fn append(self: *@This(), item: T) !void {
// ... implementation
}
};
}
// Compile-time string formatting
fn endpoint(comptime path: []const u8) []const u8 {
return "/api/v1" ++ path;
}
// Used at compile time — zero runtime cost
const users_path = endpoint("/users"); // "/api/v1/users"
C Interop (Zero-Cost)
// Import C headers directly!
const c = @cImport({
@cInclude("sqlite3.h");
});
pub fn main() !void {
var db: ?*c.sqlite3 = null;
const rc = c.sqlite3_open(":memory:", &db);
if (rc != c.SQLITE_OK) {
std.debug.print("Error: {s}\n", .{c.sqlite3_errmsg(db)});
return;
}
defer _ = c.sqlite3_close(db);
std.debug.print("SQLite version: {s}\n", .{c.sqlite3_version});
}
# Build with C library linking
zig build-exe main.zig -lsqlite3 -lc
# Use zig as a C compiler (with cross-compile!)
zig cc -o hello hello.c -target aarch64-linux
Key Features
| Feature | Details |
|---|---|
| Targets | 40+ (x86, ARM, MIPS, WASM, etc.) |
| Safety | Optional runtime safety checks |
| C interop | Direct @cImport, no bindings |
| Allocators | Explicit, pluggable |
| Build system | Built-in (build.zig) |
| Package manager | Built-in |
Resources
Building systems software? I create custom tools and data solutions. Check my Apify actors or email spinov001@gmail.com.
Top comments (0)