With async-std officially discontinued (RUSTSEC-2025-0052), the Rust async landscape has changed. The ecosystem has consolidated around two main players: Tokio and smol. Here's how to think about them in 2026.

The Players

Tokio — The Enterprise Standard

Tokio isn't just a runtime. It's a full ecosystem: runtime, futures, tracing, compression, HTTP, websockets, DNS, socks5, metrics. If you need it and it's I/O-related, Tokio probably has it.

use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    loop {
        let (mut socket, _) = listener.accept().await?;
        tokio::spawn(async move {
            let mut buf = [0; 1024];
            while let Ok(n) = socket.read(&mut buf).await {
                if n == 0 { break; }
                socket.write_all(&buf[..n]).await.unwrap();
            }
        });
    }
}

Best for: Production services, HTTP servers, anything needing a battle-tested ecosystem.

smol — The Minimalist Alternative

smol is exactly what it claims to be: a small, fast async runtime. It's the spiritual successor to async-std (same author, Stjepan Glavina).

use smol::{Async, TcpListener};
use std::net::TcpStream;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    smol::block_on(async {
        let listener = Async::<TcpListener>::bind("127.0.0.1:8080")?;
        loop {
            let (stream, _) = listener.accept().await?;
            smol::spawn(async move {
                let mut stream = stream;
                let mut buf = [0u8; 1024];
                while let Ok(n) = stream.read(&mut buf).await {
                    if n == 0 { break; }
                    stream.write_all(&buf[..n]).await.unwrap();
                }
            }).detach();
        }
        Ok(())
    })
}

Best for: Libraries, embedded systems, CLI tools, anywhere Tokio's dependency weight feels excessive.

Performance: Does It Matter?

Honestly? Usually no.

The benchmarks show tokio has a faster executor for long-running workloads. But most apps won't notice the difference. The real cost isn't runtime speed — it's what your runtime pulls in.

| Factor | Tokio | smol | |--------|-------|------| | Dependencies | ~50 crates | ~5 crates | | Compile time | Slow | Fast | | Ecosystem | Full | Minimal | | async-std compatible | No | Yes (async-adapter) |

When to Use What

Use Tokio when:

Use smol when:

The Honest Answer

For most projects in 2026, Tokio is the safe choice. It has the docs, the community, the ecosystem, and the stability. smol is excellent but requires more DIY.

The death of async-std hurt the ecosystem's diversity. But tokio and smol cover 99% of use cases. Pick one and move on.


This post was written as part of my ongoing exploration of Rust's async ecosystem. Previous: "Tokio Is a Mini Operating System".