DEV Community

Alex Spinov
Alex Spinov

Posted on

Zig Has a Free API — The Systems Language Replacing C

Zig is the systems programming language designed to replace C — with no hidden control flow, no hidden allocators, and a free, zero-overhead build system that cross-compiles to 30+ targets.

Why Zig Over C/C++/Rust?

  • No hidden control flow — every function call is explicit
  • No garbage collector — manual memory management like C, but safer
  • No undefined behavior — Zig catches what C lets through
  • Cross-compile to anythingzig build -Dtarget=x86_64-linux and done
  • C interop without FFI — import C headers directly, zero cost
  • Comptime — compile-time code execution (like C++ templates, but readable)

The Free Build System (Replaces Make/CMake)

// build.zig — this replaces your entire Makefile
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "my-app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    const run_step = b.step("run", "Run the application");
    run_step.dependOn(&run_cmd.step);
}
Enter fullscreen mode Exit fullscreen mode
# Build for current platform
zig build

# Cross-compile to Linux from macOS
zig build -Dtarget=x86_64-linux-gnu

# Cross-compile to Windows
zig build -Dtarget=x86_64-windows

# Cross-compile to ARM (Raspberry Pi)
zig build -Dtarget=aarch64-linux-gnu
Enter fullscreen mode Exit fullscreen mode

No CMake. No autoconf. No Docker for cross-compilation. One command.

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) {
        return error.SqliteError;
    }
    defer _ = c.sqlite3_close(db);

    // Use SQLite directly — no bindings, no FFI overhead
}
Enter fullscreen mode Exit fullscreen mode

Comptime (Compile-Time Execution)

const std = @import("std");

// This runs AT COMPILE TIME
fn fibonacci(n: u64) u64 {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// The result is baked into the binary — zero runtime cost
const fib_20 = comptime fibonacci(20);

pub fn main() void {
    // This prints 6765, computed at compile time
    std.debug.print("Fibonacci(20) = {d}\n", .{fib_20});
}
Enter fullscreen mode Exit fullscreen mode

No macros. No templates. Just regular Zig functions that run at compile time.

Error Handling (Better Than Go)

const std = @import("std");

const FileError = error{ NotFound, PermissionDenied, IoError };

fn readConfig(path: []const u8) FileError![]u8 {
    const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
        error.FileNotFound => return FileError.NotFound,
        error.AccessDenied => return FileError.PermissionDenied,
        else => return FileError.IoError,
    };
    defer file.close();

    return file.readToEndAlloc(std.heap.page_allocator, 1024 * 1024) catch FileError.IoError;
}

pub fn main() !void {
    const config = readConfig("config.json") catch |err| {
        std.debug.print("Error: {}\n", .{err});
        return;
    };
    std.debug.print("Config: {s}\n", .{config});
}
Enter fullscreen mode Exit fullscreen mode

Errors are values (like Go), but the compiler FORCES you to handle them.

HTTP Server in Zig

const std = @import("std");

pub fn main() !void {
    var server = std.http.Server.init(std.heap.page_allocator, .{});
    defer server.deinit();

    const address = std.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.send();
        try response.writeAll("{\"status\":\"ok\"}");
        try response.finish();
    }
}
Enter fullscreen mode Exit fullscreen mode

Zig vs C vs Rust vs Go

Feature Zig C Rust Go
Memory safety Runtime checks None Compile-time GC
Build system Built-in Make/CMake Cargo go build
Cross-compile Built-in (30+ targets) Complex toolchains Partial Built-in
C interop Direct @cImport Native FFI bindings CGo (slow)
Compile time Fast Fast Slow Fast
Error handling Error unions errno/NULL Result type Multiple returns

Need to scrape data from any website and get it in structured JSON? Check out my web scraping tools on Apify — no coding required, results in minutes.

Have a custom data extraction project? Email me at spinov001@gmail.com — I build tailored scraping solutions for businesses.

Top comments (0)