The common narrative around Rust goes like this: it’s hard to learn, especially the borrow checker, but once you internalize ownership the language gets out of your way. A recent post on the Rust blog, based on structured interviews across experience levels and domains, complicates that story in useful ways.
The challenges don’t disappear with experience; they transform. Beginners fight the borrow checker. Intermediate developers encounter async complexity. Experts hit domain walls: certification gaps for safety-critical teams, ecosystem fragmentation for embedded developers, toolchain limitations that block adoption in regulated industries. The curve doesn’t flatten; it changes shape.
The Tax Everyone Pays
Across all cohorts in the study, novices, experts, embedded developers, and network developers alike, one challenge appeared universally: compilation times. The post quotes a developer noting that Java compiles in around 100 milliseconds. Rust doesn’t.
The underlying causes are well-understood. Rust’s generics model relies on monomorphization: every instantiation of a generic function with different type parameters generates separate machine code. A function like:
fn process<T: Read + Write>(stream: T) { /* ... */ }
gets compiled independently for each concrete type T at call sites. This produces fast runtime code but multiplies the compiler’s work significantly. LLVM, Rust’s code generation backend, is itself expensive, and linking adds further cost on top of code generation. Even incremental compilation, which caches artifacts between builds, has limits: changes that touch widely-used types or trait implementations can invalidate large portions of the cache.
Progress is happening. The parallel compiler frontend, which processes crate metadata and analysis concurrently, shipped as an opt-in flag and is being progressively enabled by default. The Cranelift backend offers faster debug builds by trading optimization depth for compile speed; for teams doing iterative development, replacing LLVM with Cranelift in debug profiles can reduce build times substantially. Linker choice also matters: switching from the system linker to mold or LLD shaves meaningful seconds off incremental builds.
None of these fully resolve the problem. The monomorphization cost is fundamental to how Rust’s generics work, and for large codebases with deep dependency trees, even a fast machine with parallel compilation still imposes a productivity tax that languages with simpler compilation models don’t pay.
Async: Complexity That Accumulates
Network and web developers using Rust hit a different wall. Async Rust performs very well in benchmarks, but the conceptual surface area is large and the ecosystem carries significant fragmentation.
async/await syntax landed in Rust 1.39 in late 2019. What followed was years of gradual stabilization of surrounding features that many developers expected to ship alongside it. Async functions in traits, meaning the ability to write async fn directly inside a trait definition, were only stabilized in Rust 1.75 in December 2023, and even then with constraints around object safety that require workarounds in some use cases. Async closures, needed to pass async callbacks without boxing, arrived in Rust 1.85 in February 2025.
The runtime situation compounds the complexity. Rust has no async runtime in the standard library. Tokio dominates production network code, but async-std, smol, and Embassy each exist as alternatives with different executors. Libraries built against one runtime don’t necessarily compose cleanly with another, which in practice means most network applications end up on Tokio by default rather than by deliberate choice.
The boundary between sync and async code generates ongoing friction as well. An experienced Rust developer writing network code has to manage this boundary continuously: deciding which functions need to be async, how to bridge sync and async contexts, and how to structure types that cross that boundary. A developer writing equivalent code in Go, which has a built-in scheduler and no explicit async coloring, doesn’t face these decisions at all.
The Certification Gap
Safety-critical teams occupy a different part of the problem space. Rust’s memory safety properties make it genuinely attractive for automotive, aviation, and medical device software. The barrier is toolchain qualification. The language’s safety properties are not in question.
Certifying software under ISO 26262 for automotive or DO-178C for avionics requires that the tools used to build the software are themselves qualified. That means documented test suites, tracked known bugs, requirement traceability, and formal processes that rustc as a community-maintained open-source compiler doesn’t provide by default.
Ferrocene, the qualified Rust toolchain from Ferrous Systems, received its ISO 26262 and IEC 61508 qualification in late 2023. For the first time, a path existed to using Rust in safety-critical software under major industrial standards. Ferrocene is a commercial product with support contracts, though, not a drop-in replacement for the standard toolchain, and organizations used to Ada or C toolchains from established vendors still face procurement and validation cycles that take time.
MISRA Rust, the coding guidelines adapting MISRA’s framework to Rust, published its first version in 2024. Adoption requires static analysis tooling that can enforce the guidelines, and that tooling ecosystem is still developing. The gap between “Rust is memory safe by design” and “Rust is certifiable for use in flight control software” remains real, though it is narrowing.
Embedded: Ecosystem Maturity
Embedded developers face a challenge distinct from certification gaps but related: the distance between what is technically possible in Rust and what is production-ready with robust vendor support.
The release of embedded-hal 1.0 in December 2023 was a significant milestone. The 0.x series had served as the de facto hardware abstraction interface for years, but crates in the ecosystem made incompatible assumptions across minor versions, fragmenting driver compatibility. The 1.0 release established a stable foundation that driver crate authors could target reliably.
Embassy, the async framework for embedded systems, has matured substantially. Writing cooperative multitasking firmware in Rust using async/await without an operating system is now practical for a range of microcontrollers. The performance story holds up: async Rust on embedded can achieve interrupt latencies comparable to hand-written C state machines, with significantly better code organization.
The gap lies in vendor support. Many embedded teams work with microcontrollers whose Rust support consists of a community-maintained HAL crate with one or two active contributors. Vendor-provided SDKs remain C-centric. Debugging tooling has improved with probe-rs, but it still lags behind the mature IDE integrations available for established embedded C workflows.
What This Means for Rust’s Direction
The Rust blog’s framing reorients what the community needs to address. Onboarding improvements help beginners get past the borrow checker faster, but they don’t reduce async complexity for experienced network developers or close the certification gap for safety-critical teams.
Each of the persistent challenges has a distinct character. Compile time is a structural cost of Rust’s compilation model, addressable through incremental work on the compiler but not through language changes alone. Async fragmentation reflects an early architectural decision to keep the runtime out of the standard library, which preserved flexibility at the cost of coherence. The certification and embedded ecosystem gaps reflect the relative youth of Rust in domains where C and Ada have decades of tooling investment behind them.
The engineering manager quoted in the article put it plainly: even if none of the improvements materialized, they would remain a Rust programmer. The language’s guarantees justify the friction. Naming the friction precisely, across experience levels and domains, is what makes systematic improvement possible.