10 years of betting on Rust and what I’m looking forward to next.
I wrote my first line of Rust in June 2015, a month after Rust 1.0 landed. Coming from C, Python, and JavaScript, I never looked back. Two Rust-based startups and over 500k lines of Rust later, here are some reflections on the milestone.
The early days were painful
Version compatibility was poor, both amongst crates and with the compiler. Updating a crate for a bugfix might require updating the compiler, which required updating very unstable crates like syntex
(a dependency of serde
until custom derives). Pinning everything to versions as of a particular date helped, but binary searching for compatible version combinations was still sometimes needed. We updated the world only when necessitated by new functionality or a bugfix. This was every month or so, which seems frequent but made sense at the time given the rate at which important dependencies were evolving.
“Fighting the borrow checker” was real for me. Traits came naturally given background in C++, Java and Objective-C, but lifetimes and the idea of “proofs” that (mostly) don’t affect codegen took a while to grok. Patient friends and colleagues made this easier!
After a couple years of our codebase and team growing, compile times became painful. Large types were a recurring issue (and still are, occasionally), requiring diagnosis and mitigation. Investments brought it down for us, but iteration cycles still took a hit and rapid prototyping generally required effort to set up.
The people were and are exceptional
The Rust ecosystem has an impressive amount of programming “taste”, manifesting in dependencies with relatively simple builds, elegant implementations, and fast and robust performance. Reaching for TypeScript or Python is a relative exercise in frustration. There’s a reason Rust has taken the “most admired language” title for nine years now!
“What went right” is an essay in itself, but the evolving cadre of dedicated, opinionated and earnest volunteers, with strong mores around saying “no” and “not yet”, are I think the crux of it.
I reaped the benefits as an employer. We’ve been fortunate to be one of few Rust opportunities in London, with a pipeline of talented engineers keen to work in their favourite language. That your average Rust programmer is better than your average <most other languages> programmer has been a bonus.
Rust has become a safe bet (in some domains)
The early days necessitated a lot of yak shaving. Omissions in std
, for example, led to our evolving a library of workarounds, hacks and extensions: code that simplified or optimised our application code but wasn’t ready or wasn’t justifiable to merge upstream. Over time the rate of additions to it has slowed, and we regularly find ourselves now removing from it. Our custom implementations begone! Nowadays being able to rely upon std
’s primitives having even relatively uncommon or abstract implementations, and them be well-optimised, is a joy.
This reliability now extends to much of the Rust experience. Building and upgrading is wildly more predictable, with fewer non-Rust dependencies, ~no surprise compiletime/codegen/inlining blowups, less ecosystem reliance on nightly features and greater respecting of semver. Inference improvements have made the borrow checker friendlier to newcomers. And far fewer ICEs on nightly! We used to see new ICEs or link errors weekly, now it’s quarterly at most.
The crate ecosystem is more predictable too: crates like jiff
, polars
and tauri
learned hard lessons from prior projects. And crates like tokio
, hyper
and regex
have earned robustness through significant production usage.
Ten years ago choosing Rust for production opted you into reinventing wheels and working around known and unknown issues. While still the case for some domains - namely Rust in the browser for us - for general systems and backend engineering that is a thing of the past. Rust empowers us to focus on business logic while producing remarkably fast and robust applications.
Rust today feels like what programming should be
More than a safe bet, Rust has a degree of programmer empathy that is unprecedented in large software projects: simple and robust builds, the best error messages and linting around, great docs and IDE integration, and strong CI and regression testing. Rust feels like a passion project, a labour of love by and for programmers.
Rust today reflects the maturity and thoughtful evolution of a project born from lessons learned, mistakes corrected, and continuous refinement. The frustrations of earlier years have given way to a productive rhythm: tools and workflows now get out of your way, allowing developers to experience the joy of building high-quality software. Rust’s combination of reliability, performance, and productivity genuinely feels unparalleled. Yet, the community remains ambitious—exploring new frontiers like Rust in embedded systems, Wasm, and AI infrastructure. I’m excited for the next decade of innovation, refinement, and growth, confident that betting on Rust remains one of the best technical choices I’ve made.
What I’m looking forward to over the next 10 years
Simpler and faster builds
With growing engineering and testing bandwidth we can continue to replace battle-tested but complex or slow dependencies with simpler and faster ones. I’ve directly or indirectly benefitted from this with building and switching toolchains, linking, locks, backtraces, platform-optimised routines, TLS, HTTP, git, compression, and build automation. A few I’m particularly looking forward to gaining more attention are a pure-Rust and less special std
, reduced reliance on system linkers and libs, pure-Rust crypto, a durable BTreeMap, and a Rust game engine. The latter not for me to use but because game devs bring some of the most aggressive optimisation I’ve seen and I’d love to benefit from it.
Significant expertise and effort is going into performance work. In the last few months Tably saw a 60% compile time improvement across frontend and backend. Many of the biggest wins have come from meta changes that aren’t visible on this chart, including ThinLTO and backend parallelism, incremental, metadata pipelining, front-end parallelism. Meta changes that might bear further fruit are: Rust-oriented codegen, incremental linkers, dead-code elimination, a new solver, and cargo test
caching results.
Improved portability and less #[cfg()]
Testing the power set of valid #[cfg()]
options, targets and features on CI is generally prohibitive. This creates untested code paths and potential compile failures, alongside annoyances like fragmented and incomplete documentation, impaired IDE functionality and unused_imports
warnings.
A lint was proposed to mitigate this. A mooted better approach is moving #[cfg()]
into the trait system (cc) with bounds like where Platform: Unix
and where Platform: Avx2
. With this the compiler naturally guarantees compilation under all supported options, targets and features. Specializing items with OS-specific or architecture-specific implementations can be done via, appropriately, specialization. Metadata can be shared between dev/test/release, different feature combination and different platform builds, resulting in less recompilation, faster CI, and bringing a crates.io MIR cache closer to reality.
Everything being const
Constant evaluation reduces dependence on macros and build scripts, and brings forward run-time work and panics to compile-time. Currently we only scratch the surface of this as only a small subset of Rust code is supported (no traits, no allocation), and that which is supported runs too slowly for nontrivial use cases.
Assuming portability all code can be evaluated during compilation (cc). Unportable code like FFI or assembly without a generic fallback is getting less common. Various effects-inspired attempts to enable ubiquitous const
have been made and reverted and attempted again. I hope we dodge this extra language complexity with the simple assumption that “everything can be executed in a const
context”. There are tricky issues to overcome but the language simplicity will be worth it.
Simpler concurrency
async
has a relatively high complexity cost for us due to the 'static
bound (cc), cancellation-safety, and restrictions relating to traits and dyn
. These currently seem insoluble. Bifurcation between sync and async primitives and ecosystem idiosyncrasies further increase the async tax. Effects-inspired solutions seem unpromising.
Pre-1.0 Rust had a solution: libgreen
. It achieved concurrency in user-space without this bifurcation, but at significant performance, portability and maintenance cost and so was removed. With increased engineering bandwidth this may be worth revisiting. Again the language simplicity would be worth it. (One day I’ll create a PoC of zero-cost wrapping of std::{fs, net}
plus fiber::{spawn, select}
using generator
!)
Excelling in more domains
Rust in the browser feels under-explored: we bump into issues that suggest there aren’t many others using it seriously. Table stakes like avoiding UB and getting stack traces cross-browser took time and effort. The web framework leptos
has come a long way (as did sycamore
which we used previously) but still has rough edges.
Some domains like rapid prototyping and business logic may remain outside of Rust’s reach due to deliberate design decisions trading off iteration speed. For most domains though I think it’s a matter of time. Adoption hurdles remain for GUIs, machine learning, and game development due to entrenched ecosystems, high switching costs, cultural inertia, and established tooling. But those barriers aren’t permanent. Rust continues to mature and steadily break into these domains, thanks to relentless community efforts and innovation.
Looking forward, the trajectory is clear and exciting. The positive feedback loop of adoption boosting engineering and testing bandwidth, which then fuels further adoption, is accelerating. The upcoming decade promises further refinement, faster compile times, broader domain adoption, and an increasingly seamless developer experience. At Tably, we remain committed to pushing the boundaries of what’s possible with Rust, excited to witness—and contribute to—the language’s next chapter. Here’s to another 10 years of betting on Rust!