Jiacai Liu's personal website

My Thoughts on Bun's Rust Rewrite

  tags: zig rust bun

Table of Contents

Before we discuss Rewrite Bun in Rust, there is something that needs to be said—because no one else is saying it.

Bun stands where it does today because of Zig.

Jarred chose Zig back then not because it was "cool," but because Zig enabled a small team to rapidly prototype a high-performance JS runtime without a garbage collector or a heavy runtime. Zig's low friction, direct memory manipulation, and straightforward C interop were the core reasons Bun could punch above its weight on performance with an extremely small team in its early days. The architecture, data structures, and low-level design of Bun as it exists today were shaped by Zig.

Jarred himself said: the architecture doesn't change, and the data structures don't change.

In plain English: the skeleton that the Rust rewrite inherits was built with Zig. Building the foundation with Zig, shipping the product with Zig, raising funding with Zig, and then switching to a more "mainstream" tech stack after being acquired and growing strong—there is nothing wrong with this. It is a standard business decision. That is how tech debt is managed in Silicon Valley startups.

The Zig community doesn't need Bun's gratitude, but please don't pretend this rewrite happened because Zig itself is inadequate.

The Real Issue No One Dares to Address

Now, let's discuss the rewrite itself.

6,755 commits, branch name claude/phase-a-port, PR opened May 8th, merged May 14th.

Six days. A full rewrite of a production-grade JS runtime, merged in just six days.

Let that number sink in for a moment.

There is a fundamental principle in software engineering: code you don't understand should not run in production. Not because it is guaranteed to have bugs, but because when a bug inevitably occurs, you won't know where to start looking. This principle isn't conservatism—it's the baseline of maintainability.

6,755 commits, and not a single line was written by a human. The PR's reviewer list tells the story: coderabbitai[bot] and claude[bot] gave their approval, while the only human reviewer, alii, was still "Awaiting requested review"—he hadn't even looked.

Code written by Claude, reviewed by Claude. This closed loop isn't logically impossible, but it means no human being has actually read this codebase in its entirety.

"All Tests Pass" Doesn't Mean What You Think

Someone will push back here: the test suite passes on all platforms—isn't that validation enough?

No.

A test suite validates the correctness of known behavior on known paths. It does not validate:

  • Whether error paths are handled correctly
  • Behavior at boundary conditions under stress
  • State consistency in concurrent scenarios
  • Whether the memory model conforms to intent under extreme conditions

Jarred himself admitted that memory issues when re-entering across JS boundaries are something the Rust compiler can't handle; they still rely on human oversight.

And those parts that rely on humans? No human has reviewed them.

The more fundamental issue is that AI translates code via local semantic equivalence*—it ensures each function behaves identically to the original in isolation, but it fails to grasp the *global invariants that span functions. These are the design constraints that aren't codified in tests and live only in the original author's head. These constraints might not show up in today's tests, but could manifest six months from now under a specific production load as a completely inexplicable crash.

This isn't a knock on Claude. This is a problem any translation tool—including human programmers—faces without thorough review. At the scale of 6,755 commits, this risk is amplified 6,755 times.

After the Acquisition, the Risk Bearer Has Changed

There is a political-economy dimension here that technical discussions usually ignore.

In the early days, Bun was Jarred betting on himself. Using Zig then, iterating fast, and accepting tech debt was reasonable startup logic with self-assumed risk.

Now that Bun has been acquired by a major company and powers real production systems, the risk profile has shifted. The risk of this rewrite is no longer borne by Jarred alone, but by every engineer running Bun in production and the users they serve.

Jarred says this version is still in canary, and there is optimization and cleanup work to do before the official release.

Canary is a line of defense, but it's not a substitute for human review. Optimization and cleanup are code quality concerns, not comprehension concerns. A codebase that no one on the team has fully read—no matter how comprehensive the tests or how long the canary runs—remains a black box to its maintainers.

This will manifest as very real pain during the debugging of a future severe incident.

Zig's "Problems" Were Misdiagnosed

Let's return to Jarred's stated reasons for migration: the Zig codebase had too many use-after-free bugs, double-frees, and memory leaks on error paths.

This is true. But the conclusion that "Zig doesn't work" is the wrong diagnosis.

The correct diagnosis is: in a commercial project that prioritizes rapid iteration, the cognitive tax of manual memory management exceeded the team's budget. This isn't a bug in Zig—it's a structural mismatch between Zig's design goals and Bun's business model.

Zig’s target users are systems programmers who demand ultimate control and are willing to pay the price for it. TigerBeetle uses Zig to build a database with virtually no memory bugs because their team culture and the nature of their project align perfectly with Zig’s philosophy.

Bun's team culture is about fast iteration, fast shipping, and fast bug fixes. There is a fundamental tension between this and the rigorous memory discipline that Zig demands. This is a mismatch between Bun and Zig, not a failure of Zig.

Interpreting "our team frequently makes mistakes with this tool" as "this tool is inadequate" is an attribution error. The hammer doesn't fit, but it's not the hammer's fault.

So, Will This Rewrite Work?

Honestly: in the short term, it will probably be fine; in the long term, there are structural risks.

Short-term: tests cover the main paths, the canary phase will expose obvious issues, and Rust's compiler guarantees eliminate an entire class of memory bugs. On the surface, everything looks normal.

Long-term: this codebase has 6,755 commits that no human has fully read. When a bizarre concurrency bug appears six months from now, or when some boundary condition triggers anomalous behavior under a specific load, the engineer debugging the problem will face a system that no one has ever truly understood.

A system no one truly understands isn't necessarily bug-free; it just means that when bugs do appear, no one knows why. The difference between those two states becomes crystal clear at 3 AM during a production incident.

This is the real technical bet of this rewrite: not Zig vs. Rust, but whether AI-generated, unreviewed code can be maintained long-term in production environments.

This question is far more complex than "all tests pass," and far more profound than "Rust memory safety."

The answer? We'll wait and see.