Rust's async ecosystem fragmented around three runtimes. In 2026 Tokio dominates production. async-std faded; smol is a niche choice for embedded or library use. Understanding why helps you not pick the wrong one for a new project.
Tokio — the default
Multi-threaded work-stealing scheduler. Massive ecosystem (hyper, tonic, axum, sqlx all use it). Mature, well-documented, production-tested. The right answer for ~95% of new Rust async services.
async-std — historically
Designed to mirror std's API closely. Won mindshare 2019-2021. Lost steam as Tokio's ecosystem grew. Still maintained but new projects rarely choose it; library compatibility is harder.
smol — minimal and embeddable
Small footprint, single-threaded variant available. Right for: libraries that want to be runtime-agnostic, embedded systems, anywhere Tokio's size is a problem. The async-executor crate is its underlying primitive.
Runtime-agnostic libraries
If you're writing a library, target the futures-rs traits (Stream, AsyncRead, AsyncWrite) and let callers pick the runtime. Don't hard-depend on Tokio unless you really need it. Improves your library's reach.
When NOT async at all
CPU-bound work: use Rayon, not async. Simple multi-threaded server: regular threads + sync code may be simpler. Async is for I/O concurrency at scale. Don't async something that doesn't need it.