logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·30.10.26
← Back to news

What Zig felt like, coming from Rust

Original article
besok.github.io|119 points|126 comments|by ksec|Sep 19, 2026

Reflections on Transitioning from Rust to Zig

Introduction

Having spent the last seven years immersed in the Rust ecosystem—primarily contributing to open-source initiatives—I believe I've developed a strong intuition for the language. My personal preference leans toward the functional aspects of Rust: I value expressive type systems and the elegance of pure functions.

However, my curiosity regarding other languages led me to Zig. I've viewed it as a potential successor to C—a leaner, lower-level tool that is increasingly respected in the systems programming community. Given my early career experience with C, I felt a comparison between the two would be illuminating.

A Note on Perspective: My journey with Zig began specifically with the project described here. Consequently, some of my observations might seem elementary to seasoned Zig developers. My implementation choices were often guided by "Rust muscle memory" rather than native Zig idioms.

To ensure a balanced comparison, I decided to port a project I had already completed in Rust. I wanted something substantial enough to be useful, but not so massive that it became a sprawling odyssey. I chose JSONPath (as defined in RFC 9535). I transitioned the logic from my existing jsonpath-rust library to a new implementation: zig-jsonpath.


The IDE Shock

The most unexpected part of the transition wasn't the syntax or the memory model, but the near-total absence of IDE support. Coming from the luxury of RustRover and other JetBrains environments, I found Zig's tooling to be minimal—essentially just basic autocompletion and syntax highlighting.

While initially jarring, this forced me to return to the command line, which proved to be a refreshing experience. I rediscovered the efficiency of bare CLI tools. The centerpiece of this workflow was build.zig, which manages the project with impressive simplicity.

Common Build Commands

CommandPurpose
zig build testExecutes the full test suite
zig build test -Dfilter = "..."Runs a specific test function
zig build test -Ddebug-query = trueRuns tests with debug logging enabled
zig build complianceRuns the RFC compliance suite
zig build checkCombines unit tests and compliance checks

This shift actually triggered a broader change in my development environment. I moved away from heavy IDEs in favor of a more modular stack:

  • Helix (Editor)
  • Alacritty (Terminal)
  • Zellij (Multiplexer)

Embracing a Flat Structure

In Rust, I often agonize over the balance between file length and directory depth. The language encourages fragmenting code into deep hierarchies. While Zig allows this, it doesn't actively promote it—much like C.

I discovered that nesting files often introduces unnecessary import friction. I began asking myself: Does splitting this into five files actually improve readability?

I found that collapsing related logic into a single, larger file—and simply navigating by section—was often more efficient. If a model required a helper, I'd simply create a model_companion.zig file and keep it adjacent. While this might not scale to massive enterprise projects, the threshold for needing a complex hierarchy in Zig is much higher than I anticipated.

I used to think deep folders were mandatory for organization. Now, I realize I often organized out of habit rather than necessity.

Structural Comparison

The difference in philosophy is stark when looking at the source trees:


Testing Philosophies

If we set aside the RFC compliance suite and look at the language itself, my Rust testing strategy usually follows a simple formula: Total Tests=Inline Unit Tests+External Integration Tests\text{Total Tests} = \text{Inline Unit Tests} + \text{External Integration Tests}Total Tests=Inline Unit Tests+External Integration Tests

In Zig, the approach is similar in that you can write tests directly within the source file. However, because of the flat structure I adopted, I faced a dilemma:

  1. Create a separate model_test.zig for every model (clutters the folder).
  2. Inline the tests within the model file (clutters the code).

I ultimately chose the latter. By explicitly configuring the tests in build.zig, I was able to keep the process clean and efficient.

Testing Workflow Placeholder

Overall, the process of writing and managing tests in Zig felt more streamlined once the initial configuration was handled.

// Example of a simple Zig test block
test "basic match function" {
    const result = matchFunction("input", "pattern");
    try std.testing.expect(result == true);
}