Bun's AI-driven port from Zig to Rust
- https://www.youtube.com/watch?v=2AqwehBu84w
- Original title: I Can't Believe Rust Is Replacing Zig, Too
Bun — one of the largest Zig codebases ever written — merged an AI-driven port of its entire Zig codebase to Rust: over a million lines of Rust added to main, driven by a ~300-rule porting.md blueprint that agents followed file by file. Forrest clones the repo and reviews the result: a deliberately faithful (non-idiomatic) port that passes Bun's full test suite on all platforms, fixes memory leaks and flaky tests, shrinks the binary 3-8 MB, and benchmarks neutral-to-faster than Zig. He addresses the viral "13,000 unsafe blocks" criticism, finds spots where the Rust is actually better than the original Zig, and speculates the real motive is stabilizing Claude Code, which ships as a Bun executable (Bun was acquired by Anthropic earlier this year).
What happened
Jarred Sumner (Bun's creator) started an experiment about a week earlier to see if AI could port the Zig codebase to Rust. The merge landed with over a million lines of Rust. State of the repo at recording time:
- ~720k actual lines of Rust (excluding comments/blanks), 571k lines of Zig still present, plus TypeScript, JavaScript, C++, C.
- ~1,300 Zig files; ~1,200 have a Rust port in the same directory with the same filename (
.rsinstead of.zig). The remainder are mostly third-party Unicode libraries. - Rust and Zig coexist for now; Rust is the default and Zig will be stripped out in follow-up PRs.
The porting.md blueprint
The most interesting file in the rewrite is porting.md — the instructions AI agents read before porting each file. ~300 rules covering type mappings, idiom translations, naming conventions, banned dependencies. It opens: "You are translating one Zig file to Rust. Read this whole document before writing any code." Two phases:
- Phase A: draft
.rsfile next to the Zig file that captures the logic faithfully; it does not need to compile. - Phase B: make it compile, crate by crate.
So this is explicitly a faithful one-to-one port, not idiomatic Rust: same architecture, same data structures, few third-party libraries, no async Rust. The pre-existing cross-platform test suite is what made an accurate port possible.
Results per the merge PR
- Passes Bun's existing test suite on all platforms.
- Fixes several memory leaks and flaky tests.
- Binary size shrinks 3-8 MB.
- Benchmarks between neutral and faster (Rust beating Zig on its home turf of speed).
- Compiler-assisted tools now catch/prevent the memory bugs that had cost the team enormous development and debugging time.
- Likely closes ~200 GitHub issues, presumably because those bug classes can't exist in Rust.
Code quality review
Every ported file carries a "Ported from <file>.zig" comment so human and AI reviewers can trace provenance. Patterns Forrest observed:
- Zig is typically shorter; Rust is more explicit. E.g. an HTTP header value iterator went from 18 lines of Zig to ~33-44 lines of Rust because Zig's built-in tokenizer type has no nameable Rust equivalent (anonymous closure type), so the agent inlined its own tokenization — and left a port note explaining why. This explain-your-deviation pattern recurs throughout.
- Some Rust is better than the original: the Zig code called out to a C++ shim to get the VM pointer on every
BunVMcall; the Rust version reads the thread-local directly in one assembly instruction, eliminating 905 out-of-line call sites (cross-language LTO couldn't inline the shim), and adds a debug assertion in case the assumption breaks. - Almost no cop-outs: no
todo!()macros, a singleunimplemented!().
The unsafe-blocks controversy
A viral comparison counted 13,000+ unsafe blocks in Bun's Rust vs 73 in uv, spawning the "C++ with Rust syntax" take. Forrest's counterpoints:
- Bun embeds JavaScriptCore, libuv, uWebSockets, and several C/C++ libraries; ~2,400 unsafe blocks are unavoidable FFI bindings.
- The other ~8,000 come from faithfully porting Zig code that was already memory-unsafe: the original Zig codebase has 2,500+ raw pointer manipulations, each capable of use-after-free, aliasing violations, or misaligned access — Zig just doesn't make you type "unsafe". Rust's unsafe surface is more granular, so one Zig pointer op often becomes multiple Rust unsafe blocks.
- Jarred said the count would stabilize around 10,000 and that reducing it is ongoing work.
Verdict: not idiomatic Rust, not what you'd write from scratch — it reads like a port — but a competent one, no lower quality than the Zig it replaced, and definitely not AI slop.
Why do this at all
Beyond the obvious marketing value for parent company Anthropic (Bun was acquired by them earlier this year), Forrest thinks the real driver is Claude Code, which ships as a Bun executable and has serious memory issues — reports of the main process climbing from 1.7 GB to 14 GB in minutes, and 23 GB after 14 hours freezing a system. Not all leaks are Zig's fault (one was attributed to the WebKit malloc allocator inside JavaScriptCore, which no wrapper language controls), but the port fixes a lot. Time will tell whether Bun stays stable as the remaining Zig is removed.