Open-source project
tokio-rs/tokio avatar
tokio-rs/tokio

Tokio: the async runtime Rust services are built on

GitHub describes it as A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, .... The repository metadata lists Rust as its primary language. The metadata lists the MIT license. This article stays within the project description and details documented in the GitHub repository README.

33,211 stars3,707 forksRustMIT

At a glance

What is it?
Tokio supplies the scheduler, OS-backed reactor and async TCP/UDP sockets that Rust async code needs to run. It is the right default for network services, and the wrong tool for short command-line programs that never wait on I/O.
Who is it for?
Adopt Tokio if you are writing a Rust network service, a proxy, a database client or anything that juggles many concurrent connections, and you are on Rust 1.71 or newer. Do not adopt it for a short script that reads a file and exits, or if you cannot accept a rolling MSRV policy that moves only at minor releases.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Tokio actually solves for Rust programs

Rust gives you threads and blocking I/O out of the box. That is fine until you need ten thousand simultaneous connections, at which point one OS thread per connection stops being viable. Tokio is the layer that lets a single thread drive many sockets at once. The README describes it as an event-driven, non-blocking I/O platform, and the target audience is anyone writing a network service in Rust: HTTP servers, proxies, database clients, message consumers, anything that spends its time waiting on file descriptors rather than on the CPU.

The project does not try to be a web framework. It stops at the runtime. That boundary is deliberate and it is why the same crate sits underneath hyper, axum, tonic and warp, all of which the README lists as related projects. If you want routing and extractors, you pick a framework on top. If you want a gRPC server, you pick tonic. Tokio is the floor, not the building.

The scheduler, the reactor and who owns the socket

Tokio has three moving parts. The first is a multithreaded, work-stealing task scheduler: `tokio::spawn` puts a future onto a queue, and idle worker threads steal work from busy ones. The second is a reactor backed by the operating system event queue, which the README names as epoll, kqueue and IOCP depending on platform. The third is the async socket layer in `tokio::net`.

The data flow matters more than the component list. When you call `TcpListener::bind(...).await`, the listener is registered with the reactor. Calling `accept().await` on a socket that has no pending connection does not spin and does not block a thread. It yields the task back to the scheduler and returns control; the reactor wakes the task when the OS reports the socket readable. That is why one worker thread can service thousands of connections: the thread is only ever occupied while a task has real work to do.

Cancellation falls out of the same design. Dropping a future stops it at its next await point, and the README calls this out as a property Tokio handles naturally. It is a genuine difference from thread-based code, where killing a thread mid-operation is something most runtimes refuse to do.

Installing Tokio and running a first echo server

Tokio is a library, not a binary, so there is nothing to install system-wide. You add it as a dependency in `Cargo.toml`. The README's example enables the full feature set, which is the fastest way to get something compiling:

toml
[dependencies]
tokio = { version = "1.53.1", features = ["full"] }

The `#[tokio::main]` attribute comes from the `tokio-macros` crate and rewrites an async `main` into a synchronous one that starts the runtime, runs your future and shuts the runtime down. The README's example is a TCP echo server bound to port 8080:

rust
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];
            // read and write back, see the README for the full loop
        });
    }
}

Run it with `cargo run`, then connect from another terminal with `nc 127.0.0.1 8080`. Whatever you type should come back. The important line is `tokio::spawn`: the accept loop never waits for one client to finish before serving the next. The repository also ships runnable variants under `examples/`, including `echo-tcp.rs`, `chat.rs`, `proxy.rs` and `graceful-shutdown.rs`, each with its own `Cargo.toml` in that directory.

Where Tokio is the wrong choice

The README's own framing is a warning as much as a pitch: Tokio is a runtime for asynchronous applications. If your program does not wait on I/O, async buys you nothing and costs you a dependency and a layer of indirection. A CLI that parses arguments, reads one file and prints a result is simpler with ordinary blocking code. Wrapping it in `#[tokio::main]` adds a scheduler and a reactor that will never be used.

There is a second, sharper constraint. Blocking inside an async task stalls the worker thread that is running it, and with the multithreaded scheduler that means other tasks waiting on that thread are delayed. The README does not spell out the remedy in the excerpted text, but the crate exposes `tokio::task::spawn_blocking` for exactly this. A synchronous database driver, a CPU-heavy compression step or a call into a C library should go there, not into a plain `async` block. This is the single most common way a Tokio service degrades under load, and it does not show up in development where concurrency is low.

A third boundary is the MSRV. Tokio keeps a rolling minimum supported Rust version of at least six months and only raises it as part of a minor release. The current MSRV is 1.71, and the README lists the history back to 1.0. If you are pinned to an older toolchain for compliance reasons, you need to check that history before upgrading, and the README also notes that a transitive dependency can raise the effective MSRV even when Tokio itself has not moved.

How Tokio differs from async-std and from plain threads

The closest alternative in the Rust ecosystem is async-std, which also provides a runtime, async I/O and a task scheduler. The difference is not the API shape, since both implement the same `Future` trait and the same `AsyncRead`/`AsyncWrite` conventions. It is the surrounding ecosystem. The README lists hyper, axum, tonic, tower and tracing as projects maintained alongside Tokio, and most of the widely used Rust network libraries are written against Tokio's I/O traits. Choosing async-std usually means giving up compatibility with that stack or running a compatibility shim.

The other alternative is not a library at all: threads with blocking I/O. For a service that handles a few hundred connections, a thread pool is easier to reason about, has no async colouring problem, and produces stack traces that point at the actual blocking call. The trade-off is that thread-per-connection stops scaling somewhere in the low thousands, and Tokio's work-stealing scheduler is designed for the range above that. If your concurrency target is below that threshold, the async machinery is overhead you are choosing to pay.

Maintenance, upgrades and the MIT licence

The repository is not archived, and the last push was on 2026-07-20. The most recent release listed is tokio-1.53.1, tagged the same day, following 1.53.0 on 2026-07-17 and 1.52.4 on 2026-07-16. The project is a Cargo workspace, not a single crate: the top level contains `tokio/`, `tokio-macros/`, `tokio-stream/`, `tokio-test/` and `tokio-util/`, and the README states that each crate keeps its own changelog. Upgrading therefore means reading more than one changelog if you depend on more than one of them.

Tokio is MIT licensed, and the repository carries a `LICENSE` file at the root. That is a permissive licence, which matters if you are shipping a closed-source binary, but it is not legal advice and your own counsel should confirm attribution requirements. The workspace also contains a `deny.toml`, which is the configuration file for `cargo-deny`, a tool commonly used to audit dependency licences and advisories in CI. If you care about the licence surface of the transitive graph, that file is the place the maintainers have already encoded their policy.

The upgrade cost is mostly bounded by the semver promise. Minor releases can raise the MSRV, so a toolchain bump is the thing to check first, before the API. The workspace lints block in the root `Cargo.toml` also lists a set of `cfg` flags, including `tokio_unstable`, which gate features that are not covered by the stability guarantee. If your build sets any of them, treat upgrades as potentially breaking.

Editorial conclusion

Adopt Tokio if you are writing a Rust network service, a proxy, a database client or anything that juggles many concurrent connections, and you are on Rust 1.71 or newer. Do not adopt it for a short script that reads a file and exits, or if you cannot accept a rolling MSRV policy that moves only at minor releases. Before you commit, read the feature-flag list on docs.rs and enable only what you use, because features = ["full"] pulls in more than a minimal service needs.

Frequently asked questions

Is Tokio the same as Tokyo?

No. Tokio here is the Rust runtime maintained by the tokio-rs organisation, and the name is spelled without the second y. Tokyo is the city. The overlap in search results is a naming collision, not a relationship.

What is the meaning of Tokio?

The README does not give an origin for the name. It describes Tokio only as a runtime for writing reliable, asynchronous and slim applications with the Rust programming language, and does not explain the choice of word.

How to install Tokio in Rust?

There is no system install. You add it to `Cargo.toml` as a dependency, and the README's example uses version 1.53.1 with the full feature set enabled. Cargo fetches and builds it as part of `cargo build` or `cargo run`.

How to use tokio::spawn?

`tokio::spawn` takes a future and schedules it on the runtime, returning immediately so the calling task continues. In the README's echo server it is used inside the accept loop so each accepted socket is handled without blocking the next accept.

How to use Tokio?

The README's starting point is a Cargo dependency with the full feature set, then an async main annotated with `#[tokio::main]` that binds a `TcpListener` and spawns a task per accepted socket. Guides and API documentation are linked from the README at tokio.rs and docs.rs.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tokio-rs-tokio.svg)](https://hysenlabs.com/projects/tokio-rs-tokio)