I was debugging a memory corruption bug at 2am last Tuesday - again. The stack trace pointed to malloc() but the actual problem was 300 lines earlier where some helper function I didn't write was secretly allocating memory. No documentation, no warning, just a comment that said "// TODO: make this more efficient" from 2019.
That's why Andrew Kelley started Zig in 2016. He got tired of the same problems I've been dealing with for years: C's silent failures, cross-compilation that requires a computer science degree, and mystery allocations that show up three months later in production.
Zig 0.15.1 dropped January 27, 2025 and yes, it's still pre-1.0. Your build will break when 0.16 drops - probably around February 2026. But when it breaks, you get a clear error message and a migration guide, not a cryptic linker error during weekend deployments.
No Hidden Bullshit
The whole point of Zig: if your code doesn't look expensive, it isn't. No hidden allocations. No surprise function calls. No "why is this 5-line function calling malloc() 12 times" detective work. When something allocates memory, you can see it in the code. When production crashes, you know exactly where and why.
What Actually Works in Zig
Memory allocation you can actually debug
Remember that memory leak I mentioned? Three days tracking down a "small" allocation in a JSON parser that was happening on every request. Memory kept disappearing - something like 45MB per hour, maybe more during traffic spikes. Our monitoring was shit so hard to tell exactly. In Zig, every allocation has to pass an allocator explicitly - you can't hide malloc() calls inside helper functions. Yeah, it means typing allocator
everywhere, but when your server starts eating memory, you know exactly where to look. Haven't touched valgrind or AddressSanitizer since I switched.
Compile-time code that doesn't break your brain
C++ template error messages are the stuff of nightmares - 200 lines of garbage about "substitution failure" when you miss a semicolon. C macros are even worse. Zig's comptime just runs regular Zig code at compile time. When it breaks, you get normal error messages pointing to the actual problem. Spent most of last weekend porting this C++ template-heavy vector math thing to Zig comptime. Zig version compiles faster and when something fucks up, the error actually tells you what went wrong instead of vomiting template instantiation hell.
Cross-compilation that just works
Back in June I needed to build our server for ARM64. In C++, that meant two days of pure hell setting up a cross-compilation toolchain, hunting down ARM64 versions of dependencies, and debugging linker errors that might as well have been in Sanskrit. With Zig's toolchain, it's literally zig build -Dtarget=aarch64-linux
and you're done. Ships with libc for everything because Andrew got tired of the same toolchain bullshit we all deal with.
Your existing C/C++ code just works
Here's the insane part - the Zig compiler can replace gcc/clang and cross-compile your old C/C++ projects without changing a single line. I compiled some dusty C project for Windows on my Linux machine using zig cc
instead of the usual MinGW torture session. Took about a minute instead of half a day of dependency nonsense.
Who's Running This in Production
Yeah, people are actually shipping Zig code to real users. Not just toy projects or demos. Real production systems handling real traffic:
TigerBeetle: An accounting database that processes millions of transactions. They chose Zig because they needed C-level performance without C-level debugging hell. Their codebase is a masterclass in how Zig should be written.
Bun: JavaScript runtime that's actually fast. No GC pauses killing your server's response time. They benchmark obsessively and publish the results.
Ghostty: GPU-accelerated terminal that doesn't eat your RAM alive like Electron apps. Mitchell Hashimoto's architectural decisions are worth studying.
Uber: Using Zig to bootstrap ARM64 infrastructure because cross-compilation actually works without requiring a dedicated build farm.
The Pre-1.0 Reality
0.16 will break your build. 0.17 will break it again. That's the deal until 1.0 hits (probably late 2026). The development cycle follows LLVM releases every 6 months, and each one changes something core to the language.
But here's the difference: when Zig breaks your code, you get detailed release notes explaining exactly what changed and how to fix it. Last time I upgraded (0.14 to 0.15), it took me most of an afternoon to update our codebase. Most of that was running zig fmt
and fixing some import paths. Compare that to Python 2→3 or the Node.js ecosystem where "minor" version updates randomly break everything with no explanation.
What Actually Sucks
ZLS crashes constantly - The language server gives you basic autocomplete but crashes about twice per day. I've got VS Code set to auto-restart language servers because it happens so often. Don't expect refactoring tools or advanced IDE features.
You'll write everything yourself - The package ecosystem is basically empty. Need JSON parsing? Write it. HTTP client? Write it. Mach engine packages some C libraries, but that's about it. I spent a week writing a decent HTTP client because none of the existing ones handled our use case.
No async/await yet - They removed the old async system and the new one isn't ready. So you get threads and blocking I/O like it's 2005. Works fine, but it's not elegant.
Version pinning is mandatory - That *
in your build.zig dependencies? That'll break CI when a new version drops. I learned this when our automated builds started failing on Sunday morning because someone published a breaking change. Pin everything or suffer.