Ramblings of an aging IT geek
← Ramblings of an aging IT geek
rust

two years of rust in production, and an honest tally

An honest accounting of running Rust services in production for two years: where it earned its keep, where it cost me, and what I'd choose again.

A laptop showing Rust code on a desk

Two years ago we put our first Rust service into production. Not a rewrite-the-world job, just one data-plane component that was getting hammered and that the previous implementation kept falling over on. Long enough now to be honest about it, past the honeymoon and past the backlash, into the boring middle where you actually know things.

The short version: I'd do it again, for that workload, and I'd think harder before reaching for it on the next one.

What it actually got right

The wins are real and they're not the ones the evangelists lead with. Yes, we stopped getting the class of crash that used to wake people up, the null-deref, use-after-free, data-race sort that you can't reason your way out of at 3am. But the bigger win was quieter. The compiler made refactoring fearless. You change a type, the errors cascade, you fix them one by one, and when it builds it genuinely tends to work. We did two large internal restructures that I would simply not have attempted in our old C++ with the same confidence.

Tail latencies got predictable. No GC pauses, no surprise stop-the-world, and the memory footprint sat flat for weeks. For a thing on the critical path, that predictability was worth more than the raw throughput.

// the kind of thing that used to be a footgun, now just... fine
let total: u64 = chunks
    .par_iter()
    .map(|c| c.checksum())
    .sum();

rayon turning a sequential loop parallel with a one-word change, and the borrow checker guaranteeing I hadn't shared anything I shouldn't, still feels slightly like cheating.

What it cost

Now the regrets, because there were some.

Compile times are a tax you pay every single day. A clean build of the workspace is coffee territory. We threw sccache and a faster linker at it and it's tolerable, but "tolerable" is doing work in that sentence.

Hiring and onboarding were slower than I'd like to admit. A competent engineer is productive in Rust eventually, but "eventually" was measured in weeks of fighting the borrow checker before the mental model clicked. Lifetimes in particular are a genuine learning cliff, and pretending otherwise does new people a disservice.

And the ecosystem, whilst excellent in the hot paths, is patchy at the edges. We hit a couple of libraries that were either immature or abandoned, and async Rust specifically remains sharp in places: the error messages around futures and pinning can be properly baffling, and "just spawn a task" hides more complexity than it should.

Would I again

For this service, without hesitation. It does a narrow, performance-sensitive job, it's stable, and it almost never pages anyone. That's the job.

But Rust is not a default. It's a deliberate choice for code where correctness and predictable performance genuinely matter more than how fast you can write it. For a CRUD service that talks to a database and gets rewritten every eighteen months anyway, I'd reach for Go and not feel a flicker of guilt. The mistake isn't choosing Rust. The mistake is choosing it everywhere because it's the language you've decided to have feelings about. Match the tool to the job, and Rust is a very good tool for a specific job.