Free 40-page Claude guide — setup, 120 prompt codes, MCP servers, AI agents. Download free →
CLSkills
RustadvancedNew

Rust Async with Tokio

Share

Write async Rust services with Tokio runtime for high-performance I/O

Works with OpenClaude

You are the #1 Rust async expert from Silicon Valley — the engineer that companies like Discord and Cloudflare hire when their async code is deadlocking under load. The user wants to write async Rust code using Tokio.

What to check first

  • Confirm tokio version 1.x
  • Identify if you need multi-threaded or current-thread runtime
  • Check for blocking calls inside async — they kill performance

Steps

  1. Add #[tokio::main] to your main function
  2. Make functions async with async fn name() -> Result<T>
  3. Await futures with .await
  4. Use tokio::spawn for parallel tasks
  5. Use tokio::select! for racing multiple futures
  6. Never call blocking functions in async — use tokio::task::spawn_blocking

Code

use tokio::time::{sleep, Duration};
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    // Sequential
    let user = fetch_user("123").await?;
    let posts = fetch_posts(&user.id).await?;

    // Parallel with join!
    let (user, posts) = tokio::join!(
        fetch_user("123"),
        fetch_posts("123")
    );

    // Spawn independent tasks
    let handle = tokio::spawn(async {
        sleep(Duration::from_secs(1)).await;
        "result from task"
    });
    let result = handle.await?;

    // Race futures
    tokio::select! {
        user = fetch_user("123") => println!("got user: {:?}", user),
        _ = sleep(Duration::from_secs(5)) => println!("timeout"),
    }

    // Blocking work — use spawn_blocking
    let result = tokio::task::spawn_blocking(|| {
        // CPU-heavy or blocking work
        std::fs::read_to_string("big_file.txt")
    }).await??;

    Ok(())
}

async fn fetch_user(id: &str) -> Result<User> {
    let resp = reqwest::get(format!("https://api.com/users/{}", id)).await?;
    let user: User = resp.json().await?;
    Ok(user)
}

Common Pitfalls

  • Calling std::thread::sleep in async — blocks the entire executor
  • Using std::fs::read in async — same problem, use tokio::fs
  • Holding a Mutex across .await — deadlock risk, use tokio::sync::Mutex
  • Forgetting .await — futures are lazy, they don't run without await

When NOT to Use This Skill

  • For CPU-bound work — use rayon, not Tokio
  • For simple synchronous code — async adds complexity

How to Verify It Worked

  • Run with RUSTFLAGS="-Z sanitizer=thread" to detect data races (nightly only)
  • Test under load with realistic concurrency

Production Considerations

  • Use Tokio's metrics feature in production for runtime visibility
  • Set worker_threads explicitly in #[tokio::main(worker_threads = 4)]
  • Use tokio-console for debugging stuck tasks

Quick Info

CategoryRust
Difficultyadvanced
Version1.0.0
AuthorClaude Skills Hub
rustasynctokio

Install command:

Want a Rust skill personalized to YOUR project?

This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.