HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
tokio-rs
tokio
Rust2016–2026
tokio-rs / tokio

tokio

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

43Distinct people
49Mentions
1Explicit recommenders
33.7KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

Tokio author here. Generally speaking, I recommend strongly against using FuturesUnordered unless you know all the pitfalls. We are working on an alternative utility that…

carllerche used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 5:04:57 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year49 dated mentions

Observed mentions: 2016-08-05 18:35:46 UTC to 2026-09-14 22:05:26 UTC.

02468102016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments20162017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 10 mentions; 3 submissions, 7 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments20212022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 4 mentions; 1 submissions, 3 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC505
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC202
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC303
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC404
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC1037
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC505
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC505
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC303
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC413
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC707
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Tokio A runtime for writing reliable, asynchronous, and slim applications with the Rust programming language. It is: Fast: Tokio's zero-cost abstractions give you bare-metal performance. Reliable: Tokio leverages Rust's ownership, type system, and concurrency model to reduce bugs and ensure thread safety. Scalable: Tokio has a minimal footprint, and handles backpressure and cancellation naturally. Website | Guides | API Docs | Chat Overview Tokio is an event-driven, non-blocking I/O platform for writing asynchronous applications with the Rust programming language. At a high level, it provides a few major components: A multithreaded, work-stealing based task scheduler. A reactor backed by the operating system's event queue (epoll, kqueue, IOCP, etc.). Asynchronous TCP and UDP sockets. These components provide the runtime components necessary for building an asynchronous application. Example A basic TCP echo server with Tokio. Make sure you enable the full features of the tokio crate on Cargo.toml: [dependencies] tokio = { version = "1.54.1", features = ["full"] } Then, on your main.rs: 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]; // In a loop, read data from the socket and write the data back. loop { let n = match socket.read(&mut buf).await { // socket closed Ok(0) => return, Ok(n) => n, Err(e) => { eprintln!("failed to read from socket; err = {:?}", e); return; } }; // Write the data back if let Err(e) = socket.write_all(&buf[0..n]).await { eprintln!("failed to write to socket; err = {:?}", e); return; } } }); } } More examples can be found here. For a larger "real world" example, see the mini-redis repository. To see a list of the available feature flags that can be enabled, check our docs. Getting Help First, see if the answer to your question can be found in the Guides or the API documentation. If the answer is not there, there is an active community in the Tokio Discord server. We would be happy to try to answer your question. You can also ask your question on the discussions page. Contributing 🎈 Thanks for your help improving the project! We are so happy to have you! We have a contributing guide to help you get involved in the Tokio project. Related Projects In addition to the crates in this repository, the Tokio project also maintains several other libraries, including: toasty: An async ORM for Rust supporting both SQL and NoSQL databases. axum: A web application framework that focuses on ergonomics and modularity. hyper: A fast and correct HTTP/1.1 and HTTP/2 implementation for Rust. tonic: A gRPC over HTTP/2 implementation focused on high performance, interoperability, and flexibility. warp: A super-easy, composable, web server framework for warp speeds. tower: A library of modular and reusable components for building robust networking clients and servers. tracing (formerly tokio-trace): A framework for application-level tracing and async-aware diagnostics. mio: A low-level, cross-platform abstraction over OS I/O APIs that powers tokio. bytes: Utilities for working with bytes, including efficient byte buffers. loom: A testing tool for concurrent Rust code. Changelog The Tokio repository contains multiple crates. Each crate has its own changelog. tokio - view changelog tokio-util - view changelog tokio-stream - view changelog tokio-macros - view changelog tokio-test - view changelog Supported Rust Versions Tokio will keep a rolling MSRV (minimum supported rust version) policy of at least 6 months. When increasing the MSRV, the new Rust version must have been released at least six months ago. The current MSRV is 1.85. Note that the MSRV is not increased automatically, and only as part of a minor release. The MSRV history for past minor releases can be found below: 1.54 to now - Rust 1.85 1.48 to 1.53 - Rust 1.71 1.39 to 1.47 - Rust 1.70 1.30 to 1.38 - Rust 1.63 1.27 to 1.29 - Rust 1.56 1.17 to 1.26 - Rust 1.49 1.15 to 1.16 - Rust 1.46 1.0 to 1.14 - Rust 1.45 Note that although we try to avoid the situation where a dependency transitively increases the MSRV of Tokio, we do not guarantee that this does not happen. However, every minor release will have some set of versions of dependencies that works with the MSRV of that minor release. Release schedule Tokio doesn't follow a fixed release schedule, but we typically make one minor release each month. We make patch releases for bugfixes as necessary. Bug patching policy For the purposes of making patch releases with bugfixes, we have designated certain minor releases as LTS (long term support) releases. Whenever a bug warrants a patch release with a fix for the bug, it will be backported and released as a new patch release for each LTS minor version. Our current LTS releases are: 1.51.x - LTS release until March 2027. (MSRV 1.71) 1.53.x - LTS release until September 2027. (MSRV 1.71) Each LTS release will continue to receive backported fixes for at least a year. If you wish to use a fixed minor release in your project, we recommend that you use an LTS release. To use a fixed minor version, you can specify the version with a tilde. For example, to specify that you wish to use the newest 1.51.x patch release, you can use the following dependency specification: tokio = { version = "~1.51", features = [...] } Previous LTS releases 1.8.x - LTS release until February 2022. 1.14.x
Read the full README on GitHub

What Hacker News says

49 sources
I'm a little nervous about the correctness of the memory orderings in this project, e.g. Two acquires back to back are unnecessary here. In general, fetch_sub and fetch_add should give enough guarantees for this file in Relaxed. https://github.com/frostyplanet/crossfire-rs/blob/master/src... Congest is never written to with release, so the Acquire is never used to form a release chain: https://github.com/frostyplanet/crossfire-rs/blob/dd4a646ca9... The queue appears to close the channel twice (once per rx/tx), which is discordant with the apparent care taken with the fencing. https://github.com/frostyplanet/crossfire-rs/blob/dd4a646ca9... The author also suggests an incorrect optimization to Tokio here which suggests a lack of understanding of what the specific guarantees given are: https://github.com/tokio-rs/tokio/pull/7622 The tests do
Read the rest
not appear to simulate the queue in Loom, which would be a very, very good idea. This stuff is hard. I almost certainly made a mistake in what I've written above (edit: I did!). In practice, the queue is probably fine to use, but I wouldn't be shocked if there's a heisenbug lurking in this codebase that manifests something like: it all works fine now, but in the next LLVM version an optimization pass is added which breaks it on ARM in release mode, and after that the queue yields duplicate values in a busy loop every few million reads which is only triggered on Graviton processors. Or something. Like I said, this stuff is hard. I wrote a very detailed simulator for the Rust/C++ memory model, have implemented dozens of lockless algorithms, and I still make a mistake every time I go to write code. You need to simulate it with something like Loom to have any hope of a robust implementation. For anyone interested in learning about Rust's memory model, I can't recommend enough Rust Atomics and Locks: https://marabos.nl/atomics/
In Crossfire: High-performance lockless spsc/mpsc/mpmc channels for Rust
It's definitely a bit contrived, but to me it's also emblematic of the issues with async Rust. The note on mpsc::Sender::send losing the message on drop [1] was actually added by me [2], after I wrote the Oxide RFD on cancellations [3] that this talk is a distilled form of. So even the great folks on the Tokio project hadn't documented this particular landmine. [1] https://docs.rs/tokio/latest/tokio/sync/mpsc/struct.Sender.h... [2] https://github.com/tokio-rs/tokio/pull/5947 [3] https://rfd.shared.oxide.computer/rfd/0400
In Cancellations in async Rust
docs.rs is just barely viable because it only has to build crates once (for one set of features, one target platform etc.). What you propose would 1) have to build each create for at least the 8 Tier 1 targets, if not also the 91 Tier 2 targets. That would be either 8 or 99 binaries already. Then consider that it's difficult to anticipate which feature combinations a user will need. For example, the tokio crate has 14 features [1]. Any combination of 14 different features gives 2^14 = 16384 possible configurations that would all need to be built. Now to be fair, these feature choices are not completely independent, e.g. the "full" feature selects a bunch of other features. Taking these options out, I'm guessing that we will end up with (ballpark) 5000 reasonable configurations. Multiply that by the number of build targets, and we will nee
Read the rest
d to build either 40000 (Tier 1 only) or 495000 binaries for just this one crate. Now consider on top that the interface of dependency crates can change between versions, so the tokio crate would either have to pin exact dependency versions (which would be DLL hell and therefore version locking is not commonly used for Rust libraries) or otherwise we need to build the tokio crate separately for each dependency version change that is ABI-incompatible somewhere. But even without that, storing tens of thousands of compiled variants is very clearly untenable. Rust has very clearly chosen the path of "pay only for what you use", which is why all these library features exist in the first place. But because they do, offering prebuilt artifacts is not viable at scale. [1] https://github.com/tokio-rs/tokio/blob/master/tokio/Cargo.to...
In Rust compiler performance
The situation in Rust seems to be a bit complicated. But I did find that panicking within a thread you spawn kills just that thread and not the whole program. And it seems that Tokio has the same behavior. https://github.com/tokio-rs/tokio/issues/2002#issuecomment-6... And web frameworks like Tower provide standard ways of handling panics and turning them into error responses. https://docs.rs/tower-http/latest/tower_http/catch_panic/ind... So I don’t think panics are necessarily meant to be program-killing in Rust, even if Result types are heavily recommended instead.
In The inevitability of the borrow checker
In Rust, a library can define "features" that can be conditionally enabled or disabled when depending on it, which give a a built-in way to customize how much of the library is actually included. Tokio is a great example of this; people might be surprised to learn that the total number of direct dependencies that are required by tokio is only two[1]; everything else is optional! Unfortunately, it doesn't seem like people are super diligent about looking into the default feature set that's used by their dependencies and proactively trimming that down. It doesn't help that the syntax for pulling in extra features is less verbose than removing optional but default ones (which requires both specifying "no-default-features" and then manually adding every one of the default features that you do still want back to the list of ones you pull in),
Read the rest
and it _really_ doesn't help that the only way for libraries to expose the ability to prune unneeded features from their own dependencies to the users who inherit them is by manually making their own feature that maps to the features of every single one of their own dependencies. For example, if you're writing a library with five dependencies, and every one of them has one required dependency and four optional ones, giving the users of your library full control over what transitive features they pull in would mean making 20 features in your own library mapping to each of those transitive features, and that's not even counting the ones that you'd want to make for your own code in order to be a good citizen and not force downstream users to include all of your own code. More and more I'm coming to the opinion that the ergonomics around features being so much worse for trying to cut down on the bloat is actually the catalyst for a lot of the issues around compile times in Rust. It doesn't seem to be super widely discussed when things like this come up though, so maybe it's time that I try to write a blog post or something with my strong feelings on this so at least I'll have something to point to assuming the status quo continues indefinitely. [1]: https://github.com/tokio-rs/tokio/blob/ee19b0ed7371b069112b9...
In Build It Yourself
> if it compiles it typechecks is kind of tautological It's not tautological at all, because the type system in Rust and Haskell is not a trivial condition of the language. > not particularly effective as a saying or slogan Neither is "if it compiles it runs", rather less so in fact, everyone is sick of hearing it, and rolls their eyes so hard it's actually audible. Every one of these 764 bugs compiled and passed type checks: https://github.com/tokio-rs/tokio/labels/C-bug Not picking on tokio in particular, mind you, finding and fixing bugs is a sign of quality in a library or program. > I believe it’s meant to be more of a “works, relative to what you might expect from other languages” kind of thing versus, “is a completely perfect program.” Which is why I describe it as meaningless puffery. What you're saying here is that you know full
Read the rest
well it isn't true, but want to keep saying it anyway. My reply is find a way to express yourself which is true, rather than false. I bet you can figure one out.
In Async Rust in Three Parts
> The obvious examples you want to use work fine, but the feature needs to be designed in such a way that the language remains internally consistent and works in all edge cases. True. How long should that process take? A month? A year? Two years? I ask because this feature has been talked about since I started using rust - which (I just checked) was at the start of 2017. Thats nearly 8 years ago now. 6 years ago this RFC was written: https://rust-lang.github.io/rfcs/2497-if-let-chains.html - which fixes my issues. But it still hasn't shipped. Do I have too high expectations? Is 6 years too quick? Maybe, a decade is a reasonable amount of time to spend, to really talk through the options? Apparently 433 people contributed to Rust 1.81. Is that not enough people? Do we need more people, maybe? Would that help? Yes, I do feel piqued by the g
Read the rest
lacial progress. I don't care about the || operator here - since I don't have any instinct for what that should do. And complex match expressions are already covered by match, anyway. Rust doesn't do the obvious thing, in an obvious, common situation. If you ask me, this isn't the kind of problem that should take over 6 years to solve. > Your commentary on Pin in this post is even more sophomoric than the rest of it and mostly either wrong or off the point. I find this quite frustrating, especially since I wrote detailed posts explaining Pin and its development just a few months ago. If I'm totally off base, I'd appreciate more details and less personal insults. I've certainly given Pin an honest go. I've used Pin. I've read the documentation, gotten confused and read everything again. I've struggled to write code using it, given up, then come back to it and ultimately overcame my struggles. I've boxed so many things. So many things. The thing I've struggled with the most was writing a custom async stream wrapper around a value that changes over time. I used tokio's RwLock and broadcast channel to publish changes. My Future needed a self-referential type (because I need to hold a RwLockGuard across an async boundary). So I couldn't just write a simple, custom struct. But I also couldn't use an async function, because I needed to implement the stream trait. As far as I can tell, the only way to make that code work was to glue async fn and Futures together in a weird frankenstruct. (Is this a common pattern? For all the essays about Pin and Future out there, I haven't heard anyone talk about this.) I got the idea from how tokio implements their own stream adaptor for broadcast streams[1]. And with that, I got this hairy piece of code working. But who knows? I've written hundreds of lines of code on top of Pin. Not thousands. Maybe I still don't truly get it. I've read plenty of blog posts, with all sorts of ideas about Pin being about a place, or about a value, or a life philosophy. But - yes, I haven't yet, also read the 9000 words of essay you linked. Maybe if I do so I'll finally, finally be enlightened. But I doubt it. I think Pin is hard. If it was simple, you wouldn't have written 9000 words talking about it. As you say: > Unfortunately, [pin] has also been one of the least accessible and most misunderstood elements of async Rust. Pin foists all its complexity onto the programmer. And for that reason, I think its a bad design. Maybe it was the best option at the time. But if we're still talking about it years later - if its still confusing people so long after its introduction - then its a bad part of the language. I also suspect there are way simpler designs which could solve the problems that pin solves. Maybe I'm an idiot, and I'm not the guy who'll figure those designs out. But in that case, I'd really like to inspire smarter people than me to think about it. There's gotta be a simpler approach. It would be incredibly sad if people are still struggling with Pin long after I'm dead. [1] https://github.com/tokio-rs/tokio/blob/master/tokio-stream/s...
In Rewriting Rust
I don't think “function coloring” (which is a concept that I find overhyped and uninformative anyway, especially when talking about Rust[1]) has anything to do with the difference between stackful and stackless coroutines: it's about whether you let the language insert yield points automatically or force the programmer to spell them out explicitly. We could make the exact same thing for blocking code by the way: just create two keywords `blocking`/`block` and mark all stdlib function that do trigger a blocking syscall as `blocking` and force the programmer to use the `block` keyword and transitively annotate the calling function as `blocking` and tada! You have static enforcement of blocking code (aka function coloring) in your language without even having any kind of coroutines. It also doesn't have much to do with structured concurrency
Read the rest
either, and we could have gotten structured concurrency for free in Rust had tokio decided to cancel tasks handles on drop like futures are. And they even weren't that far of doing so[2] [1]: https://news.ycombinator.com/item?id=36497399 [2]: https://github.com/tokio-rs/tokio/issues/1830
In Thread-per-core
Regarding the quote: > The Original Sin of Rust async programming is making it multi-threaded by default. If premature optimization is the root of all evil, this is the mother of all premature optimizations, and it curses all your code with the unholy Send + 'static, or worse yet Send + Sync + 'static, which just kills all the joy of actually writing Rust. Agree about the melodramatic tone. I also don't think removing the Send + Sync really makes that big a difference. It's the 'static that bothers me the most, and that's not there because of work stealing. I want scoped concurrency. Something like <https://github.com/tokio-rs/tokio/issues/2596>. Another thing I really hate about Rust async right now is the poor instrumentation. I'm having a production problem at work right now in which some tasks just get stuck. I wish I could do the equ
Read the rest
ivalent of `gdb; thread apply all bt`. Looking forward to <https://github.com/tokio-rs/tokio/issues/5638> landing at least. It exists right now but is experimental and in my experience sometimes panics. I'm actually writing a PR today to at least use the experimental version on SIGTERM to see what's going on, on the theory that if it crashes oh well, we're shutting down anyway. Neither of these complaints would be addressed by taking away work stealing. In fact, I could keep doing down my list, and taking away work stealing wouldn't really help with much of anything.
In Thread-per-core

Showing the 15 most recent of 49 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.