On 14 May 2026 Bun replaced its Zig runtime with a Rust one in a single merge — 1,009,257 added lines, 2,188 files, six days from open to merge. This is an attempt to measure what that did to the project's defect reports, using the canary channel as a controlled before/after and the untouched stable branch as a control group.
Opened 8 May 2026, merged on the 14th. A 1,009,257-line addition against 4,024 deletions across 2,188 files — the runtime rewritten in a different language, landing in one merge rather than incrementally.
claude/phase-a-portConfirmed, not inferred: Sumner's retrospective (8 Jul 2026) says the port ran as ~50 parallel Claude Code workflows on a pre-release Claude model — 11 days end-to-end, ~$165,000 at API pricing, peaking near 1,300 lines a minute, against his one-year estimate for a human team. The claude/* branch prefix is the repo's standing convention (7,469 of 18,528 PRs carry the claude label). Disclosure that belongs beside every claim in that post: Anthropic acquired Bun in December 2025.
Merged pull requests went from 45.7/week in the six months before to 126.1/week after — ×2.76. The AI-labelled share rose from 55.5% to 75.0%. The rewrite changed the development mode, not just the language.
“It passes Bun's pre-existing test suite on all platforms … the binary size shrinks by 3 MB – 8 MB, the benchmarks are between neutral and faster … To try this, run bun upgrade --canary. Please do file issues if you run into any. … Still some optimization work to do before this lands in non-canary version.”
1.3.x-canary before the merge, 1.4.x after. The version lineage switches cleanly at the cut: not a single pre-merge issue names a 1.4.x Bun build (a plain version-string match finds nine, every one a library version like elysia 1.4.x), and 1.3.x-canary mentions stop within a week of the merge. Dashed rules are the period means for reports opened and for reports since fixed. The strip below marks every stable release — canary itself is a rolling tag with no per-build release entry, so the ticks show what reached ordinary users, which since the merge is nothing.This is the comparison that isolates the rewrite. Both sides are the same distribution channel and roughly the same kind of user — people who deliberately run pre-release Bun. The only thing that changes at the cut is the language the runtime is written in, because the Rust port went straight into canary and has never left it. The version strings confirm the handover is clean: not one pre-merge issue names a 1.4.x Bun build, and 1.3.x-canary mentions stop within a week after the merge.
Through that channel, bug reports went from 5.9 a week to 20.7 — 3.5× against the full pre-window, or 2.2× against the busier final quarter before the merge, which is the conservative read. Fixes kept pace: 41.9% of Rust-canary bug reports have been closed as fixed against 43.5% of Zig-canary ones, and 8.7 a week are now being fixed against 2.6 before. The share fixed within 30 days of filing actually improved, from 18.8% to 30.4% — Zig canary was a side branch where reports could sit for months; Rust canary is the mainline.
What this cannot separate is how many people are reporting. Two things changed at the cut besides the language. Canary became the only way to get the Rust build, so the population behind those 20.7 reports a week is almost certainly larger than the population behind 5.9. And the PR asked for reports in as many words — “Please do file issues if you run into any” — which lifts the reporting rate independently of how many defects exist. Report volume is exposure × defect density × willingness to report, and only the product is observable. A ×2.2–3.5 rise is therefore an upper bound on any rise in defect density, not a measurement of it.
The ratios are the sturdier half of the finding. Fix rate and fix latency don't depend on how many people are looking: 41.9% against 43.5%, with 30-day resolution improving. Whatever the Rust port is generating, the team is clearing it at the rate it always did — while merging 126 pull requests a week against 46 before.
The repo-wide total is motionless — 69.3 a week before, 68.9 after — and that is the least informative number in this study. It holds still because two populations moved in opposite directions by almost exactly the same amount: canary reports rose by 14.8 a week, and reports naming only a stable 1.3.x build fell by 14.3. Bun did not stop receiving bugs at the old rate; it stopped receiving them about the same code. Any analysis of this rewrite that stops at the repo total will conclude nothing happened.
The stable side is the natural control group. Nothing in 1.3.14 changed after 13 May — it is the same Zig binary every stable user is still running — and reports about it fell 31.2%, with the fix rate slipping from 42.6% to 39.2%. That's what a codebase looks like when the people who maintain it have moved to something else.
2.01/month, median gap 16 days: v1.3.3 through v1.3.14. Already a slowdown — the same calendar window a year earlier shipped 25 releases at a 5-day median gap.
The newest stable tag is bun-v1.3.14, 13 May 2026 — one day before #30412 landed. The longest gap between any two Bun releases in all of 2024–2026 was 27 days, against a median of 8. The current gap is 89 days and open-ended.
Everyone on stable is running Zig code that is no longer being actively fixed; everyone on canary is running Rust code that cannot be installed by default. On the evidence here the rewrite's measurable cost so far is not a defect spike — it's that the two halves of the user base have been on different runtimes for three months, exactly as the PR said they would be until the optimization work lands.
The hypothesis this study set out against: Rust's whole-language rigidity and complexity — borrow checker, lifetimes, trait system, syntax, static types included — make it badly suited to everyday development, where tasks are rarely precisely defined and unexpected cases demand flexibility. That position is neither fringe nor strawman. It is held by senior practitioners with serious Rust mileage, by the designers of Go and of Zig — the language Bun left — and, in part, by Rust's own creator. The production record at scale points the other way. Every quote below was fetched from its source and verified on 10 Aug 2026.
What is striking is that the two camps agree on where the boundary sits. The fiercest critique concedes it: “Rust fits very nicely in the low level algorithmic areas where one knows exactly what the problem is and just needs to solve it” (LogLog Games, the same essay). An ex-AAA engine developer in the same thread: “Rust excels when you know what you want to build… Once you get up in game logic/behavior that iteration loop is so dynamic that you are prototyping more than developing.” The disagreement is not really about Rust. It is about which regime the work lives in. The complexity tax is front-loaded — paid during exploration, while requirements churn. The strictness dividend is back-loaded — collected in production, as defect classes that never ship. Which side of the ledger dominates depends on how much of the work is exploration and how much is execution against a known spec.
Two scope notes keep this honest. Zig is also a statically-typed, compiled language — so this case measures the increment of ownership, lifetimes and traits, not “static versus dynamic typing,” and the static-typing literature is left out of this discussion as a different question. And a JavaScript runtime that embeds JavaScriptCore over FFI keeps a substantial unsafe surface where the borrow checker's guarantees lapse — “use-after-free becomes a compile error” is a property of safe Rust, not of the FFI boundary where much of a runtime's hottest code lives.
The rigidity argument has always been an argument about human iteration speed — the cost of fighting the compiler while exploring. This rewrite changes who does the fighting. Per Sumner's retrospective and press reporting: ~50 parallel Claude Code workflows on a pre-release Claude model, 11 days end-to-end, ~$165,000 at API pricing, a peak near 1,300 lines a minute, 100% of the test suite passing — against his estimate of “a small team of engineers a full year.” (Disclosure, his and ours: Anthropic acquired Bun in December 2025, and this study was itself researched and written with Claude.)
The peer-reviewed evidence leans Sumner's way on the narrow question: constraining LLM decoding with type-system rules cuts compilation errors by more than half (ETH Zürich / UC Berkeley, PLDI 2025), and an LLM iterating against rustc's error messages fixes roughly 74% of real-world compile errors unaided (Microsoft Research, ICSE 2025). In an agent loop, the strict compiler converges instead of blocking. Against that stand Ronacher's hands-on results — and Kelley's objection, which is not about Rust at all: compilation proves the absence of certain bug classes, not the presence of understanding. Nobody has read the million lines.
This study's numbers adjudicate a little of both. The language did not become the bottleneck — bug-fix throughput held at pre-rewrite rates against triple the canary report volume, with 2.76× the merge rate. The human loop did: triage collapsed and nothing has shipped to stable in 89 days. Machines absorbed the complexity tax. Humans kept the verification bill.
unsafe surface outside the borrow checker's guarantees. Kelley's counter-hypothesis (culture, not language: stable Zig projects exist) also survives this data untouched. Anyone citing this rewrite as proof about Rust for everyday, vaguely-specified development — in either direction — is overclaiming.| Period | Weeks | Canary | Stable 1.3.x only | All bug reports | Releases/mo | |||
|---|---|---|---|---|---|---|---|---|
| per wk | fix rate | per wk | fix rate | per wk | fix rate | |||
| Pre-rewrite baseline | −26 … −1 | 5.92 | 43.5% | 45.77 | 42.6% | 69.31 | 40.8% | 2.01 |
| …final quarter only | −13 … −1 | 9.38 | 41.8% | 48.15 | 42.0% | 69.62 | 42.3% | 1.67 |
| ▼ PR #30412 — Rewrite Bun in Rust — merged 2026-05-14 08:09 UTC · canary switches from 1.3.x to 1.4.x | ||||||||
| Post-rewrite, month 1 | 0 … 3 | 21.75 | 47.1% | 32.50 | 30.0% | 80.50 | 38.5% | 0 |
| Post-rewrite, month 2 | 4 … 7 | 21.00 | 41.7% | 31.75 | 42.5% | 66.25 | 41.1% | 0 |
| Post-rewrite, month 3 | 8 … 11 | 19.25 | 36.4% | 30.25 | 45.5% | 60.00 | 39.6% | 0 |
| Post-rewrite, all | 0 … 11 | 20.67 | 41.9% | 31.50 | 39.2% | 68.92 | 39.7% | 0 |
| Change vs baseline | — | ×3.49 | −1.6 pt | −31.2% | −3.4 pt | −0.6% | −1.1 pt | −100% |
| Wk | Week starting | Canary | fixed | Stable only | fixed | No version | All bugs | Release |
|---|
Source. All 2,981 issues (pull requests excluded by construction) created in oven-sh/bun between 2025-11-13 and 2026-08-10, pulled via the GitHub GraphQL API with createdAt, closedAt, state, stateReason, labels, author and body text. Release dates come from the Releases API — all 214 are marked non-prerelease. Totals were cross-checked against the Search API. The frozen snapshot, every analysis script, and an independent verification script that re-derives all 31 published figures from that snapshot live in the companion repository.
Binning. Weeks are 7×86400s bins anchored to the merge timestamp rather than to calendar weeks, so week −1 is the last seven days before the rewrite and week 0 the first seven after. Week −26 begins 2025-11-13, six months before the merge. Week +12 covers five days and is excluded from every average.
What counts as a bug report. Every issue not labelled enhancement, docs, idea, question, chore, duplicate, invalid or wontfix — 1,802 before the rewrite and 827 after. Whether an issue was triaged is irrelevant; only that it was opened. The bug label is deliberately not used as the definition, because label coverage collapsed across the cut (unlabelled share went from 0–3% in November 2025 to 50–63% after the rewrite), so a bug-label count measures triage effort rather than defect reports.
Which build a report is about. Classified from version strings in the title and body — Bun's issue template asks for bun --revision, so most reports carry one. Canary = the text matches 1.3.x-canary (Zig canary) or 1.4.x (the Rust line, which has never had a stable release). Stable only = matches 1.3.x with no canary suffix and no 1.4.x mention. No version stated = neither. Coverage is stable across the cut — 25.4% unclassified before, 24.3% after — so the split is not an artifact of reporting habits changing. Robustness: a stricter classifier that only accepts a 1.4.x token carrying canary/debug/a build hash, or sitting within 80 characters of bun/version/revision, moves the counts from 154→147 pre and 248→246 post, leaves both fix rates unchanged to one decimal, and raises the volume ratio from ×3.49 to ×3.63 — the published looser rule is the conservative choice. The false matches are library versions (elysia 1.4.x, tw-animate-css 1.4.0, WCAG criterion 1.4.3), and in a 25-issue random sample of post-rewrite canary classifications, 23 were the reporter's own bun --revision output.
What counts as fixed. GitHub's stateReason of COMPLETED on a closed issue. The 19 issues closed and later reopened count as open, not fixed. Headline fix rates compare final states as of the pull date, which penalises the younger cohort; the 30-day figures ask the same question of every week — what share was fixed within 30 days — over weeks old enough to answer it.
The limit that matters most. Report volume is exposure × defect density × willingness to report, and only the product is observable. Two of those three terms changed at the cut independently of the code: canary became the only route to the Rust build, and the PR explicitly solicited reports (“Please do file issues if you run into any”). The ×2.2–3.5 rise in canary reports is therefore an upper bound on any rise in defect density, not a measurement of it. The ratios — fix rate, fix latency — are population-independent and are the sturdier half of the analysis. Severity is unweighted throughout: a segfault and a typo count the same.
On calling the rewrite AI-assisted. Initially inferred from convention (the claude/phase-a-port branch; 7,469 of the repo's 18,528 PRs carry a claude label, 75% of everything merged since the rewrite), later confirmed directly: Sumner's 8 July 2026 retrospective states the port used a pre-release Claude model across ~50 parallel Claude Code workflows, and The Register reports 11 days and ~$165,000 at API pricing. Disclosures that cut in both directions: Anthropic acquired Bun in December 2025, and this study was itself researched and written with Claude.
On the quotes in sections 4–6. Every quotation was fetched from its source URL and verified verbatim on 10 Aug 2026, with one exception: Graydon Hoare's Dreamwidth post resisted re-fetching and is paraphrased, never quoted. Authors were included only where the page or an easily-found bio evidences roughly five or more years of professional software experience; institutional data (Google, Microsoft, Dropbox, the Rust surveys, peer-reviewed papers) is cited as data rather than opinion. The static-vs-dynamic-typing literature was researched and deliberately excluded: Zig and Rust are both statically typed, so that debate is orthogonal to this case.