How to run Rust async code with Tokio

Rust async functions return futures that need an executor before their .await points make progress. Tokio provides that runtime for Rust applications that need async timers, sockets, tasks, channels, or other non-blocking work inside a normal Cargo binary.

The #[tokio::main] attribute starts a Tokio runtime before main runs. A small command-line program can use that attribute, add only the Tokio features it needs, and then call async functions with .await from the entry point.

Start from an existing binary Cargo project. A timer-backed async function gives the runtime a real awaited task to drive, and cargo run --quiet should print one success line without showing build output.

Steps to run Rust async code with Tokio:

  1. Add Tokio with the macro, multi-thread runtime, and timer features.
    $ cargo add tokio@1 --features macros,rt-multi-thread,time

    tokio@1 keeps the dependency on the current Tokio 1.x line. The macros feature enables #[tokio::main], rt-multi-thread enables the default multi-thread runtime, and time enables tokio::time::sleep.

  2. Check the dependency entry in Cargo.toml.
    $ cat Cargo.toml
    [package]
    name = "async-tokio-demo"
    version = "0.1.0"
    edition = "2024"
    
    [dependencies]
    tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }

    Your package name, version, and edition can differ. The Tokio dependency line is the part to verify.

  3. Replace the binary entry point with an async Tokio main.
    src/main.rs
    use tokio::time::{sleep, Duration};
     
    async fn fetch_message() -> String {
        sleep(Duration::from_millis(250)).await;
        "async task finished".to_string()
    }
     
    #[tokio::main]
    async fn main() {
        let message = fetch_message().await;
        println!("{message}");
    }

    The call to fetch_message().await yields to the runtime until the timer completes, then continues inside main.

  4. Run the async program through Cargo.
    $ cargo run --quiet
    async task finished

    If tokio::time or #[tokio::main] is not found, recheck the Tokio features in Cargo.toml before changing the Rust source.