
TL;DR
Richard Feldman's team rewrote the Roc compiler from Rust to Zig in 487 days. The memory safety numbers challenge assumptions, and the 35ms incremental rebuilds are real. Here's the full breakdown.
Richard Feldman just published a detailed post-mortem on rewriting the Roc programming language compiler from Rust to Zig. The rewrite took 487 days and covered roughly 300,000 lines of code. The headline numbers: 35ms incremental rebuilds in Zig vs 3.4 seconds in Rust, and - counter to what you might expect - fewer memory corruption bugs in the Zig version.
The Roc team hit architectural problems that made incremental fixes impractical. Specifically, they struggled with implementing "lambda set resolution" - a system that enables closure captures without heap allocations. As Feldman explained: "the root of our problems was architectural across several compiler phases, and fixing it would require rewriting most of the compiler."
Multiple contributors were already planning partial rewrites. The team decided that if they were going to rewrite anyway, they should evaluate whether Rust was still the right choice.
The team evaluated four factors:
Build times: This was the killer feature. Zig's -fincremental flag rebuilds a 450K+ line codebase in approximately 35 milliseconds. Rust 1.97.0's incremental builds on the same codebase take 3.4 seconds - about 100x slower.
Memory control: Zig's ecosystem assumes fine-grained allocators and struct-of-arrays layouts throughout. Rust's ecosystem largely assumes a single global allocator. Roc uses "a variety of different memory allocators throughout compilation," making Zig's approach a better fit.
Ecosystem relevance: The Zig compiler contains LLVM bitcode serialization code that Roc could reuse directly. No equivalent was available in the Rust ecosystem.
Unsafe code support: The original Rust compiler had about 1,200 uses of unsafe. Zig's additional safety checks for index-based memory access seemed more helpful for their use case than Rust's borrow checker.
This is where it gets interesting. Conventional wisdom says Rust's borrow checker should catch more bugs than Zig's manual memory management. Here's what actually happened:
| Category | Rust Compiler | Zig Compiler |
|---|---|---|
| Memory corruption bugs | 21 | 10 |
| Total bugs reported | 2,596 | 431 |
Wait - how did the unsafe language have fewer memory bugs?
Context matters. The 21 Rust bugs weren't from unsafe code blocks in the compiler itself. They were miscompilations - bugs in the generated machine code that caused memory corruption when the compiled program ran. That's a fundamentally different category than memory unsafety in the compiler process.
The 2 memory-related bugs in the Zig compiler were use-after-free issues in error reporting code. Both would have been caught by Rust's borrow checker. But both were also minor in impact - they caused malformed error messages, not security vulnerabilities.
Feldman's conclusion: "after 18 months of development, hundreds of total bug reports, and hundreds of thousands of lines of code... picking a different row would have made no appreciable difference to the project."
Newsletter
Get the weekly deep dive
Tutorials on Claude Code, AI agents, and dev tools, delivered free every week.
From the archive
Jul 15, 2026 • 7 min read
Jul 15, 2026 • 7 min read
Jul 15, 2026 • 6 min read
Jul 15, 2026 • 6 min read
The Hacker News discussion generated 92+ comments focused heavily on the technical details.
Pushback on the "unsafe compilers" framing: Steve Klabnik (Rust core team, author of The Rust Programming Language book) questioned Feldman's claim that "for compilers which emit machine code, doing memory-unsafe things is a big part of the job." His point: emitting machine code isn't unsafe - you're just writing bytes. It's executing that code that introduces unsafety. A compiler can absolutely be fully safe Rust while producing unsafe binaries.
The scheduling argument: One commenter claimed Go's runtime scheduler is "literally the most sophisticated scheduling engine in the world" and that Go can outperform Rust on throughput despite theoretical disadvantages. This generated significant pushback, with others noting that Erlang, JVM, and CLR runtimes have comparable or better schedulers.
Adding a borrow checker to Zig: Multiple commenters discussed whether Zig could gain Rust-like safety guarantees. The consensus: it's theoretically possible but would require fundamental language changes. Zig's lack of private fields, for example, makes encapsulating unsafe code impossible.
Rust build times improving: A commenter linked to Rust's 2026 roadmap for fast builds. Many of the goals are targeted for this year, suggesting the gap may narrow.
| Version | Lines of Code | Cold Build | Incremental |
|---|---|---|---|
| Rust 1.85.0 | 354K | 32.4s | 10.0s |
| Rust 1.97.0 | 354K | 25.4s | 3.4s |
| Zig 0.16.0 (at parity) | 320K | 39.6s | 8.6s |
| Zig 0.17.0 (current) | 464K | 32.1s | 0.035s |
The 35ms incremental rebuild in Zig 0.17.0 is dramatic. However, this depends on -fincremental support which still has bugs preventing stable release. The 8.6s incremental time in Zig 0.16.0 is more representative of what's available today.
Rust's 1.97.0 numbers show the language is improving - incremental builds dropped from 10s to 3.4s between versions. But the gap to Zig's target numbers remains large.
The Roc team implemented what Feldman calls "programming without pointers" - using 32-bit array indices instead of pointers throughout the compiler. This enables a clever optimization: cached compiler data structures can be loaded directly from disk without parsing, matching memcpy speeds when data is in the OS cache.
This technique is common in game programming and is used by Zig's own compiler. It eliminates serialization/deserialization overhead entirely for frequently accessed data.
defer statements in Zig)This rewrite challenges the binary "safe vs fast" framing that often dominates language discussions. A few observations:
Memory safety guarantees don't prevent miscompilation bugs. Most of Roc's memory corruption bugs weren't from unsafe compiler code - they were from the compiler generating incorrect output. The borrow checker doesn't help with that.
Ecosystem assumptions matter. Zig's allocator-everywhere pattern was a better fit for Roc's architecture than Rust's global-allocator-by-default. Sometimes the language that's theoretically "safer" isn't the language that helps you write better code in practice.
Incremental compilation is a productivity multiplier. 35ms rebuilds vs 3.4s rebuilds is the difference between flow state and context switching. That developer experience improvement may matter more than theoretical safety properties for a compiler project.
Roc is targeting a 0.1.0 release later in 2026. The codebase has grown to approximately 464,000 lines of Zig code. Whether the rewrite ultimately pays off will depend on Roc's adoption - but the data on the rewrite itself is now public and detailed enough to inform other teams making similar decisions.
Read next
Andrew Kelley's blunt response to Anthropic's AI-assisted Bun rewrite sparked debate about AI marketing, language choices, and what makes engineering decisions honest.
7 min readThe Bun runtime completed an AI-assisted rewrite from Zig to Rust, fixing memory safety issues and improving performance. Here is what HN thinks and why it matters for LLM-assisted code migration.
6 min readA Rust reimplementation of PostgreSQL now passes all 46,000+ queries in the Postgres regression suite. Here is what the project actually delivers, what it does not, and why the HN discussion reveals deeper questions about AI-assisted rewrites.
8 min readTechnical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.
Interactive timeline showing what's in context at each turn.
Claude CodeWhat MCP servers are, how they work, and how to build your own in 5 minutes.
AI AgentsA practical walk-through of how to design, write, and ship a Claude Code skill - from choosing when to trigger, through allowed-tools, to the steps the agent will actually follow.
Getting Started
Andrew Kelley's blunt response to Anthropic's AI-assisted Bun rewrite sparked debate about AI marketing, language choice...

The HashiCorp co-founder explains why he chose Zig over Rust for Ghostty, the technical challenges of terminal emulator...

Douglas Thain's Introduction to Compilers and Language Design is a free undergraduate textbook that walks you through bu...

A Haskell Foundation board member explains why Scarf moved to Python after 7 years in production. The culprit: LLM-drive...

The Bun runtime completed an AI-assisted rewrite from Zig to Rust, fixing memory safety issues and improving performance...

A Rust reimplementation of PostgreSQL now passes all 46,000+ queries in the Postgres regression suite. Here is what the...

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.