Why We Chose Zig Over Rust

The case for Zig's explicit simplicity over Rust's complexity in building sovereign systems.

zigrustlanguageengineeringsystemstechnical

Why We Chose Zig Over Rust

Everyone asks: “Why not Rust?”

Rust is memory-safe. Rust is fast. Rust has a massive ecosystem.

We chose Zig anyway.


The Rust Tax

Rust is an excellent language. For certain problems, it’s the best tool available.

But Rust comes with tax:

TaxCost
Compile timesMinutes, not seconds
Binary size500KB+ minimum (std)
Cognitive loadBorrow checker fights
Build complexityCargo, crates.io, features
Async complexityPin, Box, lifetimes everywhere

For sovereign infrastructure, these taxes compound.

What We Need

Our requirements for Libertaria:

  1. Deterministic builds – Reproducible across platforms
  2. Small binaries – Kenya Rule (<10MB, ideally <1MB)
  3. Fast compile – Iterate quickly
  4. No hidden allocations – Explicit memory management
  5. C interop – Zero-cost FFI for crypto libraries
  6. Readable code – Auditable by humans

Rust can do all of these. But Zig does them simply.

Zig’s Simplicity

const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const slice = try allocator.alloc(u8, 100);
defer allocator.free(slice);
// No hidden allocations. Ever.
}

Compare to Rust:

use std::alloc::{GlobalAlloc, Layout, System};
fn main() {
unsafe {
let layout = Layout::from_size_align(100, 1).unwrap();
let ptr = System.alloc(layout);
// ... use ptr ...
System.dealloc(ptr, layout);
}
}

Rust requires unsafe for explicit allocation. Zig makes it the default.

Comptime vs. Macros

Rust macros are powerful. They’re also complex:

macro_rules! vec {
($($x:expr),*) => {
{
let mut temp_vec = Vec::new();
$(temp_vec.push($x);)*
temp_vec
}
};
}

Zig comptime:

fn makeArray(comptime T: type, comptime size: usize) [size]T {
var arr: [size]T = undefined;
// ... fill arr ...
return arr;
}

Comptime is just Zig code that runs at compile time. No special syntax. No macro_rules.

The Build System

Rust: Cargo.toml, features, workspaces, proc-macros.

Zig:

build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "libertaria",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
}

That’s it. No crates.io dependency hell. No feature flags.

When Rust Wins

We’re not Rust haters. Use Rust when:

  • You need absolute memory safety (no unsafe allowed)
  • You’re building for a team with Rust expertise
  • The ecosystem has critical libraries
  • Compile times don’t matter

For us, explicit over safe is the right tradeoff.

The Real Reason

Rust optimizes for “prevent all bugs.”

Zig optimizes for “make all costs visible.”

We want visibility. We want to see every allocation, every system call, every edge case.

Sovereign infrastructure demands transparency.


Zig: The last language you’ll need to learn.

#zig #rust #systems #technical