DEV Community

Cover image for I counted every Bun bug before and after the Rust rewrite
Alex
Alex

Posted on • Originally published at asmyshlyaev177.dev

I counted every Bun bug before and after the Rust rewrite

On May 14, Bun merged PR #30412. One pull request: 1,009,257 lines added, 2,188 files changed. The entire runtime, ported from Zig to Rust in 11 days by roughly 50 parallel Claude Code workflows, at about $165,000 in API costs. Jarred Sumner figures a human team would have needed a year.

Reactions split exactly how you'd guess. Andrew Kelley, Zig's creator, called it "a million lines of unreviewed slop". Rust people called it the future. Three months of arguing, and as far as I can tell, nobody on either side pulled the actual numbers.

So I did. Every issue filed against oven-sh/bun from six months before the merge until last week: 2,981 of them, bucketed into weeks anchored on the merge timestamp, each one classified by which build the reporter was running. The dataset and scripts live in this repo, and there's a much drier interactive report with every chart, if you want to check my work.

What the tracker shows

The pitch for the rewrite was memory safety. Bun's tracker was drowning in use-after-free and double-free crashes, and in safe Rust those are compile errors. Sumner put the whole thesis in one line: "Compiler errors are a better feedback loop than a style guide."

Canary is where you test that claim, because canary is the only channel where the Rust build has ever shipped. Same channel, same self-selected users who run prereleases, Zig builds before May 14, Rust builds after. The cut is unusually clean: I checked every version string in six months of pre-merge issues, and not one names a 1.4.x Bun build. A grep finds nine matches, and all nine turn out to be library versions like elysia 1.4.x. The 1.4 line simply did not exist for users until the morning of the merge.

Bug reports on canary went from 5.9 a week to 20.7. I don't read that as "Rust tripled the bugs", because two other things changed at the same moment: canary became the only way to get the new engine, so its population grew, and the PR literally asked people to file issues. Report volume is exposure times defect rate times willingness to report, and you only ever observe the product.

The ratios don't care about population size though, and they're stubborn:

  • Before the rewrite, 43.5% of canary bug reports eventually got closed as fixed. After: 41.9%.
  • Canary bugs fixed per week: 2.6 before, 8.7 after. Proportional to the report flood, not better.
  • Median time to fix across all bug reports: 2.7 days before, 3.2 after.

Same machine, three times the input.

Before you reach for the obvious objection: I stress-tested the classifier. A stricter rule that only accepts a version string in real Bun context (a build hash, or next to the template's "What version of Bun is running?") moves the counts by under 1% and leaves both fix rates identical to one decimal. If anything it makes the jump slightly bigger, 3.6x instead of 3.5x. The repo has the robustness script and an independent verification that re-derives all 31 published figures from the frozen data.

Meanwhile the process around the code seized up. Last November, only 1–3% of new Bun issues went unlabeled; triage was already slipping through spring, and since the merge roughly half of new issues never get a label at all. Bun shipped 12 stable releases in the six months before May 14. Since: zero, in 89 days. The longest gap between any two Bun releases across 2024–2026 had been 27 days. Every stable user today still runs the Zig binary the project supposedly left behind.

Whether that's caution or paralysis I can't tell from outside. Probably some of both.

This was Rust's best-case scenario

The flat fix rate gets interesting once you notice the conditions it happened under.

A port is the friendliest possible job for a rigid language. The spec was frozen: behave exactly like old Bun. A million-assertion TypeScript test suite sat there as an oracle, checking every step. For 11 days, the requirements did not move. Even people who can't stand Rust concede it this territory. The much-shared "Leaving Rust gamedev after 3 years" essay, written by someone with over 100k lines of Rust behind them, says it flat out: "Rust fits very nicely in the low level algorithmic areas where one knows exactly what the problem is and just needs to solve it."

So Rust got its dream conditions, plus an AI to absorb every borrow checker complaint, and delivered a fix rate identical to the Zig era and a release pipeline in a coma.

Your project is not a port

This is where I stop reporting and start arguing.

I've spent over a decade building software, mostly products, and almost none of it resembled that port. There was no oracle. The spec was a Slack thread and a mockup. Requirements changed the first time a user touched the feature, then changed again. Half the job was finding out what we were supposed to build, usually by building the wrong thing first.

That's the regime where language rigidity hurts, and the people saying so are not beginners who bounced off the borrow checker in week one. The gamedev essay again: "the borrow checker forces a refactor at the most inconvenient times." John Nagle, of Nagle's algorithm, some 45k lines of Rust into a metaverse client, seconds it: "It's quite common for some change to require extensive plumbing work", noting the C#/Unity teams on the same problem move faster than he does. A 25-year veteran of Epic and Valve spent 14 months building his game on Rust, redid it in Unity in six weeks, and shipped. Graydon Hoare, the man who created Rust, wrote in 2023 that shipped Rust is far from the language he wanted, that he'd argued against explicit lifetimes, first-class borrows, and the trait system. And in Rust's own annual survey, the top worry among its users about the language's future is "Rust becoming too complex", at 43%.

Rob Pike caught endless grief for his reason Go is simple: "our programmers are Googlers, they're not researchers... They're not capable of understanding a brilliant language but we want to use them to build good software." Every time I reread that quote it sounds less like an insult and more like the only statement in language design anchored in how teams actually work. Your teammates are busy and distracted. So are you, so am I. A language that assumes otherwise sends the bill exactly when a deadline and a requirement change arrive together.

Steelman break

The counterevidence is real and I won't hide it. Google reports Rust changes in Android roll back 4x less often than C++ and spend 25% less time in review; across 1,000+ of their developers they found no productivity penalty. Dropbox rewrote its sync engine, the most edge-case-infested thing they own, in Rust and called the bet a force multiplier.

Look at what those wins share, though. Android platform code and a file-sync engine are among the most precisely specified software in existence. The invariants are known before anyone writes a line. Both camps in this fight agree on the boundary without noticing they agree: when you know exactly what you're building, rigidity is scaffolding. When you don't, you're paying interest on it every sprint.

The question was never "is Rust good". It's what share of your roadmap is spec-frozen execution versus "we'll understand this feature after we ship it twice". Be honest about the split. On most teams I've seen, it's one part execution to five parts figuring things out.

"But AI pays the complexity tax now"

The newest argument for maximal rigidity: language difficulty stopped mattering, because agents write the code and the compiler verifies them. There's real research behind it. An LLM looping on rustc's error messages fixes about 74% of real-world compile errors on its own. Constrain the model's decoding with the type system and compile errors drop by more than half.

Bun is the largest field test of that thesis to date, and the result is lopsided: the machine half worked and the human half didn't. Claude satisfied the borrow checker a million lines' worth. Then triage collapsed, review became the choke point, and nothing shipped for three months. Kelley's jab lands here whether you like Zig or not: "It's not sufficient to catch bugs in Zig code but it is sufficient to catch bugs in [a] million lines of unreviewed slop?"

Worth adding: Armin Ronacher, who ran Rust in production at Sentry for years, experiments constantly with coding agents and recommends Go for them, not Rust. In his tests, putting strict type checking inside the agent loop made results worse.

A compiler can prove what the code does. It can't prove that's what the code was for. That second question is the entire job, it stays with humans, and no amount of language rigidity shrinks it.

Where I land

Disclosures first, because this story is soaked in them: Anthropic acquired Bun in December 2025, the rewrite ran on a prerelease Claude model, Sumner's speed and cost numbers are self-reported, and I did this analysis with Claude's help too.

But the data as of today says: in the single most favorable setup a rigid language will ever get, frozen spec, perfect oracle, tireless AI labor, it produced no measurable improvement in how bugs get handled, while the humans around it lost the ability to ship. Your project runs with none of those advantages. Your spec moves weekly. Your oracle is whatever the PM remembers agreeing to. Your test suite is not a million assertions.

Pick the strict, complex language when the problem is genuinely pinned down. It will hold the line for you there. For everything else, and I think that's most software, complexity is a tax collected on every change, and the compiler's certainty is always about yesterday's requirements.

The numbers, the scripts, and the full study are in the repo. If you think I've read the data wrong, that's what the comments are for.

Top comments (0)