Skip to main content
← /writing
  • #ai-economics
  • #ai-strategy
  • #engineering-leadership

Everyone Knows You Never Rewrite

For twenty-six years, the full rewrite was the cardinal sin of software engineering. Then one engineer ported half a million lines of Bun from Zig to Rust in eleven days. The taboo was never about code. It was a price tag, and for systems whose intent lives in an executable oracle, the price just collapsed.

Vinny Carpenter18 min read3.6k words

Audio overview

Generated with Google NotebookLM · 20:10

Every developer I know keeps the same private tally, and I have been adding to mine for thirty years. The first version of anything you write teaches you the problem. The second teaches you the design. The third is the one you meant to write all along. I learned that the expensive way, by rewriting my own work until it said what I meant. A muddled first pass became a cleaner second, and once in a while I earned a third, the version that comes out close to perfect. The pattern has never failed me, across programming languages, companies, and architectures. And for most of those thirty years, the industry's answer has been firm: you don't get a third version.

We even have scripture for this. In April 2000, Joel Spolsky watched Netscape ship the first beta of a browser it had spent almost three years rewriting from scratch. He named the decision "the single worst strategic mistake that any software company can make." There was never a Netscape 5.0, and the market share never came back.

His reasoning was airtight. Old code looks ugly because it is dense with hard-won knowledge, and every strange branch may be a bug fix you already paid for. A rewrite trades that learning for years of standing still while competitors move. "Things You Should Never Do" became the restraining order an entire profession served on itself. For a quarter century, when an engineer arrived with a proposal titled "v2 Architecture" and that familiar gleam, my job was to quote Joel and redirect the energy into refactoring.

Here is the uncomfortable part: I was enforcing a rule my own tally argued against, and the rule was right anyway. For twenty-six years, the economics kept it that way.

Then the price changed.

Why We Lived in Version 1.5

The rewrite taboo was never really about code quality. It was about economics, and underneath the economics sat a problem older than software: we cannot fully say what we mean before we see it.

Requirements change because working software is how human beings discover their own intent. You show someone the thing they asked for, and only then do they learn what they actually wanted. Agile survived by shortening the distance between a statement of intent and the software that tests it.

Every delta between what we built and what we meant got a polite name: technical debt. Strip away the euphemism and much legacy code is fossilized misunderstanding, wrapped in the patches that made it survivable. Some reflects rational tradeoffs made under old constraints. All of it carries accumulated behavior, including behavior nobody intended but somebody now depends on.

The honest fix was often a third version, written with better knowledge of both the problem and the design. But the industry priced that version at a team-year of frozen roadmap, seasoned with Fred Brooks' second-system effect and a Chesterton's fence 500,000 lines long. Jarred Sumner put the consequence plainly in his own postmortem: until very recently, choosing a programming language was a one-way decision for a project of real size.

I wrote a book arguing that the bottleneck is never the stack; it is our ability to express intent. The rewrite taboo was that bottleneck wearing a price tag. We did not refuse third versions because we did not want them. We refused because we had no affordable way to prove that a new implementation still meant everything the old one had learned.

Eleven Days in May

On July 8, Sumner published the postmortem of rewriting Bun from Zig to Rust. Bun is not a toy. It is a JavaScript runtime, bundler, test runner, and package manager whose CLI sees more than 22 million downloads a month. Its 535,496 lines of Zig took five years to accumulate.

The disclosure sits at the top of his post, and it belongs at the top of mine. Anthropic acquired Bun in December 2025, Sumner and the Bun team work at Anthropic, and the rewrite ran on a pre-release Claude model. Read every number that follows with that in mind. I did.

The numbers still land. One engineer, monitoring about 50 dynamic workflows in Claude Code, ported all 1,448 Zig files to Rust in 11 days. The branch ran from May 3 to a merged pull request on May 14. The run produced 6,502 commits and a final diff of just over one million lines. At peak, four worktrees each ran 16 Claude agents, roughly 64 in parallel, writing about 1,300 lines per minute.

The compute came to around $165,000 at API pricing, a modeled figure rather than an invoice, since the model's owner also owns Bun. Sumner estimated that a conventional rewrite would have required three engineers with full context for about a year, during which they could fix no bugs and ship no features. The manual version would never have been approved. The realistic alternative was to keep patching forever.

Sumner did not prompt Claude to rewrite Bun and hope for the best. He spent three hours defining how Zig patterns and types should map into Rust, serialized the decisions into a porting guide, and created a separately reviewed map of struct lifetimes. He tested the method on three files before committing to all 1,448.

He paired every implementing agent with two adversarial reviewers in separate context windows. The reviewers saw the diff, not the implementer's reasoning, with instructions to assume the code was wrong. The Claude that writes the code wants to merge it; the Claude that reviews it wants to find the flaw. That is the same bias split we manage in human teams, engineered into the loop.

When agents started running git stash over each other's work, he changed the workflow rules rather than hand-fixing the damage. When compilation broke, roughly 16,000 compiler errors became a literal work queue, divided among the agents crate by crate. He corrected process defects at the source instead of repairing outputs one at a time. Two days after the first CI run, the failing test files had dropped from 972 to 23. Three days later, all six platforms went green.

My favorite detail in the writeup is a bug, because it is exactly the kind of bug a thirty-year developer feels in their spine. Zig's assert is a function, so its argument runs in every build. Rust's debug_assert! is a macro, and release builds erase the entire expression. The port translated one into the other faithfully, and an insert into the hot-reload graph vanished from release builds. Hot module reloading broke in production while working perfectly in debug.

The two snippets read as twins and behave as strangers. That bug class is why the rewrite introduced 19 known regressions, each since fixed, and why the honest version of this story includes them.

The early results are substantial. The Bun v1.4.0 canary fixes 128 bugs that still reproduce in v1.3.14. In a benchmark that rebuilds a project 2,000 times, memory levels off at 609 MB instead of reaching 6,745 MB. Binaries are about 20% smaller on Linux and Windows, and measured workloads run 2% to 5% faster. About 4% of the Rust sits in unsafe blocks, mostly single-line calls into C libraries, with 11 rounds of security review and around-the-clock fuzzing layered on since the merge.

The strongest evidence is quieter. Claude Code has shipped on the Rust port since mid-June, its Linux startup got 10% faster, and almost nobody noticed. That is what a successful rewrite is supposed to feel like.

Not everyone applauded. Andrew Kelley, Zig's creator, published a blunt response arguing that Bun's stability problems came from engineering practices rather than from Zig. He also argued that the announcement doubled as marketing for Bun's new owner. I will come back to him, because he deserves better than a dismissal.

The eleven-day number gets the attention. The test suite explains why it worked.

The Oracle, Not the Model

A conformance suite is intent made executable.

That sentence is the whole essay, so let me earn it. Bun's rewrite was possible because its test suite happened to be written in TypeScript, which means the tests never cared what language sat underneath them. On the day the port merged, 1.39 million expect() calls across roughly 60,000 tests passed, with zero tests skipped or deleted. Five years of user bug reports, edge cases, and 3 a.m. fixes had been continuously converted into executable statements of what Bun means. The agents did not have to rediscover that intent. They inherited it.

Postgres publishes its oracle outright: a regression suite whose expected outputs encode four decades of corner cases. SQLite, the most rigorously tested database in the world, keeps its deepest suite private. Hold that thought; it is about to matter.

This is my book's thesis meeting the news cycle. The constraint on software was never the stack, and it turns out it was never simply the labor either. It was our ability to express intent in a form that survives translation.

Specifications do this for the software we are about to build. I have argued that the spec is the product. Conformance suites do it for software we have already built. Schemas, API contracts, production traces, operational telemetry, and formal models can all contribute, but the test suite is usually the richest executable specification a team already owns.

Every test your team wrote was tuition converted into transferable knowledge. The exchange rate just moved dramatically in your favor.

A Pattern, Not an Anecdote

If Bun were the only data point, this essay would be a press release with extra steps. It is not the only data point.

Earlier this month, a database engineer named Michael Malis announced pgrust: a Rust rewrite of Postgres, built with collaborator Jason Seibel and a fleet of coding agents. It matches Postgres's expected output across all 46,000-plus queries of the version 18.3 regression suite, passes the isolation tests, and can boot from an existing Postgres data directory.

This week Malis published the honest version of how: four attempts over three months, about $100,000 of agent compute by his own accounting, and a graveyard of instructive failures. An early attempt rebuilt Postgres feature by feature from scratch. It reached 96% of the test suite and then died of what Malis calls organ transplant failure. The internals were subtly the wrong shape, in ways no single test revealed until the hardest subsystem rejected them.

The attempt that worked went the other direction. A mechanical transpile of Postgres's C into ugly, unsafe Rust passed the full regression suite almost immediately. It then became the base for months of crate-by-crate refinement into idiomatic Rust. His README states the strategy in eight words I would frame on a wall: "keep the real Postgres tests as the oracle."

He is equally plain about the caveats: the public version is v0.1, it is not production ready, existing Postgres extensions are not generally compatible yet, and by his own measurement it runs about 8x slower than Postgres. Malis says a faster fifth attempt is in development, but it is not yet available for independent scrutiny.

Meanwhile, Turso has been rewriting SQLite in Rust since the end of 2024, with a company behind it and none of the eleven-day drama. Turso originally chose to fork SQLite rather than rewrite it, precisely because of the lead time a rewrite demanded. When the team committed to the rewrite, it confronted the fact I asked you to hold: there was no public oracle to inherit.

So Turso built its own verification universe: deterministic simulation testing designed in from day one, a partnership with Antithesis to inject faults under a deterministic hypervisor, and public fuzzing against SQLite's own bytecode output. A year and a half in, the engine remains in beta, and the maintainers say plainly that it is not yet production ready. That is not failure. It is the visible cost of building the oracle while building the product.

Line the three up and the pattern sharpens. Bun had the owner, a faithful translation strategy, and an exceptional oracle, and it reached production workloads in weeks. Two outsiders with a public oracle and honest limits produced pgrust, a compatible but immature v0.1. Turso had an experienced company and no inheritable oracle, and it has spent years building the verification SQLite never published. What separates the projects is not whether a massive rewrite is technically possible. It is who owns the target, how stable the interfaces are, how rigorous the process is, and, above everything else, whether a trustworthy oracle exists.

The Queue Forming in Open Source

Once you see the selection function, you can predict where the economics move first: systems with high memory-safety pain, broad usage, stable behavior, and a public oracle to port against.

Some of it has already shipped through largely human effort. Ubuntu made sudo-rs the default in 25.10, and its 26.04 LTS runs Rust coreutils as the default. Memory-safe rewrites of the most-executed commands on Earth just entered a release supported for over a decade. The traditional implementations remain available for compatibility and fallback.

Those ports took years, which is exactly what makes them the baseline the new economics gets measured against. DARPA saw this coming before the tooling existed. Its TRACTOR program exists to automate translating legacy C into Rust using software analysis and machine learning, including large language models. The program's premise is blunt: manual translation takes years and costs sums nobody will approve.

The obvious candidates are the C libraries that parse untrusted input for a living: TLS stacks, image and media codecs, compression and archive formats. They carry the industry's scar tissue, most of them have serious public test suites, and every one of them just became portable in the sense this essay cares about. I will not pretend to know which project goes next, and some maintainers will oppose these rewrites on principled grounds. But I no longer bet against the selection function.

The Enterprise Estate

This is the section I am most qualified to write. I have spent the last eight years leading cloud and platform engineering at a Fortune 100 financial services company. That means I have spent eight years in rooms where someone eventually says, "We can't touch that system." That sentence has been load-bearing in enterprise IT for decades, and it is starting to expire, but not for the reason the demos imply.

The enterprise legacy estate makes Bun look like a weekend project: COBOL and PL/I batch systems older than their operators' careers, Java monoliths from the early 2000s, and integration layers nobody fully maps. Estimates of how much COBOL still runs in production vary so widely that the honest summary is that nobody knows, and it is enormous.

Enterprise rewrites have failed harder than open-source ones for a reason beyond cost. Open-source projects at least have tests. The typical legacy system's only complete specification is its own running behavior. The documentation drifted, the authors retired, and Hyrum's Law operates at full strength. Somewhere downstream, a process depends on the exact side effects of the 2 a.m. batch job, and nobody wrote that down. There is no oracle. There is only the fence, with no record of why it was built.

So the enterprise lesson is emphatically not "point agents at the COBOL." Read the Bun, pgrust, and Turso stories again and the sequence becomes clear: the oracle came first, and each port succeeded to the degree its oracle deserved trust. For a legacy estate, that inverts the modernization playbook. Step one is archaeology: characterization tests that pin down what the system actually does today, golden files from production runs, shadow traffic, and differential testing between old and new. Record the contracts that exist in production, not only the contracts somebody remembers intending.

That work used to be the unaffordable prerequisite buried inside every failed modernization program. The quieter story of 2026 is that the same agents that write the port can help build the characterization tests. Oracle construction itself just became cheaper, and that, more than any porting demo, changes the enterprise math.

Three consequences follow for leaders. First, modernization portfolios deserve a re-estimate. A five-year systems-integrator program carries assumptions about translation labor that may no longer hold, and your vendors know it. The conversation should shift from bodies per month to behavior captured, oracles built, risk retired, and evidence produced.

Second, the bottleneck moves from writing capacity to verification capacity. In a regulated industry, the real work of an agentic rewrite is provenance, security review, audit trails, operational resilience, and the human judgment that decides what "matches" means. Fund the reviewers and the gates, not just the generation. I have made this argument before about daily delivery, and a rewrite is that argument at maximum intensity: trust the gate, not the actor.

Third, you can begin to score the estate. Rewrite readiness is oracle quality multiplied by interface stability multiplied by owner commitment, and anything multiplied by zero is zero. That little formula will not survive contact with an architecture review board unmodified, but it will start the right fight.

The Skeptic Gets the Floor

Four objections deserve better than a paragraph of hand-waving, so here they are with my honest answers.

Passing tests is not correctness. True, and Bun proves it against itself. Nineteen regressions slipped through 1.39 million assertions, including code that looked nearly identical and behaved differently. Hyrum's Law guarantees the tail exists. The counterargument is not that the tail disappears. It is that human rewrites carry the same tail with less instrumentation, and that the agentic loop fixes the process that produced the bug, not just the bug. Continuous fuzzing, differential testing, production telemetry, and fast rollback create a different posture than hoping the migration team found every hidden dependency.

Who maintains a million generated lines? Sumner's answer is that a mechanical port reads like the original, so anyone who understood the Zig can understand the Rust. Malis's failed first attempt is the caution that makes the answer credible: code shaped subtly wrong died because its differences hid where no test looked. Maintainability is a property you select for in the process, not a gift the model hands you.

Community and trust do not transfer with the code. This is the sharpest objection, and I have no rebuttal, only a distinction. Postgres is not a codebase. It is a decades-old institution of committers, reviewers, extension authors, operators, and release discipline, and pgrust inherits none of it by passing the tests. A rewrite by a project's owner and a rewrite of someone else's project are different products, whatever the diff says. Bun shipped because Bun's owner did the work and then stood behind it in production.

The language was never the problem. Kelley's core argument is that Bun's bugs came from engineering values and practices, and that better discipline in Zig could have improved the system without a million-line rewrite. He is at least half right. Some reported gains came from engineering changes that were not unique to Rust. The rewrite's clearest purchase was moving a class of enforcement from style guides and vigilance into the compiler. Whether that purchase justified the churn is a judgment call, not a law of nature. The marketing gravity matters too. The model's vendor owns the showcase; discount every number accordingly.

Three things would change my mind about this essay: Bun v1.4 posting a worse defect rate than the Zig baseline over the next year, oracle-first enterprise pilots losing to incremental modernization on cost and risk, or these generated codebases proving unmaintainable by their second birthday. I will report back either way.

The Taboo Was a Price Tag

Return to the tally. The first version teaches you the problem. The second teaches you the design. The third is the one you meant to write, and for my entire career, that third version was a luxury few organizations could justify.

Spolsky was right about the risk, and he stayed right while the cost of faithful translation remained prohibitive. AI has now collapsed part of that cost, but only part. What remains is the constraint that mattered all along: saying what we mean in a form a machine can check.

The teams that spent years writing tests were not doing chores. They were converting bugs, edge cases, and production scars into institutional memory that survives a change in language, architecture, or implementation.

So the leadership agenda writes itself. Audit the estate for oracle quality. Fund conformance suites like the capital assets they are. Price verification, not generation. Re-estimate the modernization programs built on yesterday's labor assumptions. And retire "we can't touch that system" slowly, deliberately, and only as fast as your evidence deserves.

Sumner ends his postmortem with a sentence that reads differently depending on your seat: "One engineer can do a lot more today than a year ago." From where I sit, leading a few hundred engineers, it is not really a sentence about the engineer. It is a sentence about the fence between the software we have and the software we meant. For thirty years, the third version was the one we owed ourselves and rarely got to write. That debt just came due, payable in tests.


Related Reading

// found this useful? share it

Post on X Share to LinkedIn
Vinny Carpenter

Written by Vinny Carpenter

VP Engineering · 30+ years building software

I lead engineering teams building cloud-native platforms at a Fortune 100 company. I write about engineering leadership, AI-assisted development, platform strategy, and the hard lessons that come from shipping at scale.

keep reading