The conventional wisdom about Rust has always been that the learning curve is steep but finite. Fight with the borrow checker long enough, internalize ownership and lifetimes, and eventually the language gets out of your way. The Rust team’s recent study of developer challenges complicates that story considerably.
What they found, across developers at every experience level and in every domain, is that challenges don’t resolve with expertise so much as they transform. Beginners struggle with ownership. Intermediate developers hit async complexity. Experts face domain-specific walls: certification gaps in safety-critical industries, immature toolchains in embedded, architectural limitations when modeling certain graph or state-machine patterns. The “smooth sailing” phase turns out to be more of a plateau before the next set of problems.
That framing matters because it changes how you think about Rust’s future. The language doesn’t just need better error messages and onboarding. It needs structural improvements across several independent problem spaces simultaneously.
Compilation Performance Doesn’t Discriminate
One finding stands out for being universal: everyone, regardless of background or domain, cited compilation times as a meaningful productivity drain. The quote in the post captures the feeling well enough. A Java developer comes to Rust and immediately loses the fast feedback loop they’d built their workflow around.
This is a well-documented problem with a multi-factor root cause. Rust’s monomorphization model means that each generic instantiation produces separate LLVM IR, which the backend must then optimize and compile. A crate like serde with heavy derive macros and deep generic usage can generate an enormous amount of IR before a single line of your application code gets processed. Clean builds of moderate-sized Rust projects routinely take 30 to 60 seconds on developer hardware, where equivalent Go or C code builds in a fraction of that.
The incremental compilation story is better. After the initial build, recompiling after small changes is fast. But incremental compilation has had correctness issues over the years, and the psychological cost of that first clean build, or the build after switching branches, adds up across a working day.
Several approaches are in progress. The parallel frontend, stabilized in Rust 1.80, reduces wall-clock time by compiling independent modules concurrently, with real-world improvements of 20 to 50 percent depending on crate structure. The Cranelift backend offers a faster compilation path for debug builds by bypassing LLVM entirely; it generates less optimized code but compiles 2 to 4 times faster, which is exactly what you want during development. Using lld or mold instead of the system linker can also cut link times by 3 to 5 times and is now explicitly recommended in the official documentation for local development.
None of these solutions are complete. Cranelift is not yet stable-channel. The parallel frontend helps but doesn’t close the gap with Go or Java on cold builds. This is an engineering problem the Rust team knows well and is actively working on, but it’s a hard one.
Async Is Stable, Ergonomic It Is Not
For network developers, the study identifies async programming as the dominant domain-specific friction point. This makes sense. Web services, database clients, and distributed systems in Rust lean heavily on async/await, and the runtime ecosystem remains fragmented in ways that create real incompatibilities.
The stabilization of async fn in traits in Rust 1.75 was a significant milestone, but it introduced new problems while solving old ones. The async-trait crate’s approach of boxing futures was ergonomically poor but at least consistent. Native async traits use return-position impl Trait, which means each implementation produces a distinct, unnameable future type. This breaks object safety, so dyn Trait with async methods still requires explicit boxing. The Send bound problem persists: writing async code that works correctly with multi-threaded executors like Tokio requires futures to be Send, but the compiler’s ability to infer and enforce this in generic contexts is limited, producing error messages that remain opaque even to experienced developers.
The deeper issue is executor fragmentation. Tokio, async-std, smol, and embassy all implement their own executor models, and a library written for one doesn’t automatically work with another. The standard library defines Future but provides no async I/O traits, no executor interface, and no runtime. The ecosystem has been gradually converging around Tokio, but the lack of standardized async I/O traits means that crate interoperability remains a practical concern when composing dependencies.
This is the kind of problem that Rust’s RFC process needs to address at the language and standard library level. Ecosystem convergence alone won’t fix it.
Safety-Critical Domains Have a Different Kind of Problem
For teams adopting Rust in safety-critical contexts, automotive, avionics, medical devices, the challenges are less about language ergonomics and more about certification infrastructure. These industries operate under standards like ISO 26262, IEC 61508, and DO-178C, which require qualified toolchains, coding standards, and formal documentation of the development process.
Ferrocene, the joint effort by Ferrous Systems and AdaCore, achieved ISO 26262 ASIL-D qualification for the Rust compiler in 2024. That’s a meaningful accomplishment. But compiler qualification is a necessary condition, not a sufficient one. The Rust standard library and even core lack formal qualification, which means safety-critical code typically must operate in no_std environments and rely only on manually audited or formally qualified libraries. The absence of a recognized coding standard analogous to MISRA C is another gap. Formal verification tools like Kani (from AWS) and Creusot exist and are maturing, but none have achieved acceptance by major certification bodies.
Safety-critical adoption of Rust is possible, and it is happening in practice, but it demands significant investment in tooling and process that many organizations aren’t prepared for. The study’s finding that certification gaps are a persistent expert-level concern reflects the reality that Rust’s safety story in these domains is still being built.
Embedded Development Has Its Own Maturity Ceiling
The embedded Rust ecosystem has made substantial progress over the past few years. The embedded-hal abstraction layer, the probe-rs debugging toolkit, and the embassy async executor for microcontrollers have collectively raised the floor significantly. Writing safe, idiomatic Rust for a Cortex-M device is no longer the research project it was in 2018.
But the ceiling is still lower than C in several practical dimensions. Vendor HAL support is inconsistent; the quality and completeness of device support crates varies widely depending on the chip manufacturer and whether a community contributor has done the work. IDE and debugging tooling, while improved, lags behind what mature C toolchains offer for embedded targets. Binary size remains a concern for constrained targets, though techniques like link-time optimization and #[no_std] builds with custom allocators give developers meaningful control.
These are ecosystem maturity issues more than language issues, but the distinction matters less to developers trying to ship products on a deadline.
What to Do With This
The study’s framing of challenges as shifting rather than resolving is useful because it clarifies what kinds of interventions actually help. Improving error messages and adding new rustlings exercises addresses beginner onboarding, but it does nothing for the async runtime fragmentation or the certification gap. Each problem domain needs solutions targeted at the specific friction its developers encounter.
The Rust team’s response to their own research is what matters next. The compilation performance work is ongoing and directionally correct, even if incomplete. The async ecosystem needs standardized I/O traits in the standard library, a problem the async working group is actively tracking. Safety-critical adoption needs continued investment in compiler qualification and the development of a formal coding standard. Embedded needs sustained ecosystem work on vendor HAL coverage and tooling.
The quote from the engineering manager near the top of the post is worth sitting with: even with all these challenges unresolved, experienced practitioners stay. Rust provides something valuable enough that developers absorb significant friction to keep using it. That’s a strong foundation. But it’s not a reason to accept the friction as permanent.
The language is ten years past its 1.0 release and still working through structural limitations that were known early. That’s not a failure story; it’s the ordinary pace of systems language evolution. The more honest framing of Rust’s situation is that it’s a mature language with a set of well-characterized, hard problems, and the community is making real progress on most of them. Whether that progress is fast enough depends entirely on what you’re trying to build.