Stop Blaming musl for Your Slow Rust Binaries. Do This Instead.

You’ve probably been here: you build a sleek Rust binary, drop it into a FROM scratch Docker container, and pat yourself on the back for eliminating bloat. You’ve achieved the holy grail of portability. Then, the benchmarks hit. Your self-contained app is dragging its feet, running significantly slower than its glibc counterpart. You feel the anxiety of shipping a slow product, and you immediately blame musl.

But what if I told you the narrative that “musl is inherently slow” is a lie? We’ve been fed this binary choice: you can either have a tiny, self-contained binary, or you can have a fast application. You can’t have both. It’s a contradiction that forces developers to choose between convenience and speed.

Static linking isn’t your performance tax; your memory allocator is.

Most developers treat “musl is slower” as a monolithic truth. They see the benchmark, abandon their FROM scratch dreams, and go back to bloated base images. But they are treating a fixable implementation detail as a fundamental law of computing. When you actually profile a musl-linked Rust binary, the real culprit becomes glaringly obvious. The bottleneck isn’t the static linking. It’s the default memory allocator that ships with musl.

We’ve been blaming the wrong suspect, burning down our deployment simplicity to save performance that was never actually lost.

The anxiety of shipping a fast, small binary is real, but the solution isn’t to abandon musl. The actionable insight is to separate the libc from the allocator. Musl’s appeal has always been simplicity and portability. Its performance penalty forces a choice—but that contradiction dissolves the moment you swap out the default allocator for a high-performance alternative like mimalloc or jemalloc.

I saw this firsthand in the discussions surrounding the Brokk.ai analysis. One developer nailed the reality: “Most of musl’s performance issues come from their allocator. Using it with a third party high performance allocator allows you to benefit from static linking with very little performance loss.”

You don’t have to choose between a tiny container and a fast application. The tradeoff is an illusion.

The next time you see a benchmark telling you to drop musl for performance reasons, look closer. Is it actually testing the libc, or is it just exposing a weak memory allocator? Stop accepting the false compromise. Keep your static binaries, keep your FROM scratch deployment model, and fix the allocator instead. Your users—and your container registry—will thank you.

FAQ

Q: Doesn't swapping allocators defeat the purpose of using a minimal libc like musl?

A: Not at all. Musl gives you a lightweight, portable, and statically linkable foundation. A high-performance allocator like jemalloc or mimalloc just replaces the memory management layer. You still get the tiny binary and FROM scratch deployment; you just drop the slow memory management.

Q: What's the practical implication for my Rust binaries?

A: You can ship single, self-contained executables in scratch Docker containers without silently accepting a 20-30% performance tax. You configure your Rust project to use a high-performance global allocator, compile to musl, and keep your speed and your portability.

Q: Is the 'musl is slow' debate just a distraction then?

A: Exactly. The entire musl vs glibc performance debate is largely a proxy war for default allocator performance. If the industry had standardized musl with a better allocator years ago, this myth would never exist.

📎 Source: View Source