Flume: a Rust MPMC channel in casual maintenance mode
A safe and fast multi-producer, multi-consumer channel.
At a glance
- What is it?
- Flume is a multi-producer, multi-consumer channel for Rust that the README describes as a drop-in replacement for std::sync::mpsc. It is feature-complete and explicitly in casual maintenance mode, which changes how you should evaluate it.
- Who is it for?
- Adopt Flume if you need MPMC semantics, a Send + Sync + Clone sender and receiver, or async mixing on top of a codebase already shaped like std::sync::mpsc. Do not adopt it expecting new features: the README states that heavy feature development has stopped and only critical security and bug fixes continue, so anything you need beyond the current API has to come from your own PR.
- Can I use it commercially?
- Yes. Apache-2.0 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 55 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 October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Flume solves that std::sync::mpsc does not
Rust's standard library channel is single-consumer. The moment two worker threads need to pull from the same queue, you either wrap the receiver in a mutex or move to a third-party crate. Flume targets that gap directly: the README describes it as a multi-producer, multi-consumer channel and lists MPMC support as one of the reasons to pick it over the standard library. It also states that Sender and Receiver both implement Send + Sync + Clone, so handles can be duplicated and handed to threads or tasks without an outer lock.
The intended audience is Rust engineers already writing threaded or async message passing and hitting the limits of the standard channel. The README frames the migration as mechanical: it calls Flume a drop-in replacement for std::sync::mpsc. That claim is worth reading carefully rather than literally. The API shapes are familiar, but Flume adds send timeouts and deadlines, an async API, and a select-like interface, none of which exist in the standard library. You get more surface area, not a smaller one.
Queues, features and how the crate is put together
Three queue types are documented: unbounded, bounded and rendezvous. The choice is made at construction time, and the README's example uses flume::unbounded(), which returns a (tx, rx) pair. Bounded queues block or fail depending on the call you pick, and rendezvous queues are the zero-capacity case where a send and a receive have to meet.
The optional behaviour is gated behind Cargo features declared in Cargo.toml. spin swaps in spinlocks instead of OS-level synchronisation primitives internally; the README hedges on this, saying it may be more performant on a small number of platforms for specific workloads, which is honest and also a warning that it is not a default win. select adds the Selector API so one thread can wait on several channels or operations at once. async adds the async API, including on otherwise synchronous channels. eventual-fairness uses randomness in the Selector implementation to avoid biasing certain events over others.
The default feature set is async, select and eventual-fairness. That matters for dependency weight: async pulls in futures-sink and futures-core, and eventual-fairness pulls in fastrand. If you only need blocking MPMC channels, setting default-features = false removes all three. The crate itself depends on spin 0.9.8 for its mutex, and the package declares rust-version = 1.78.0, so older toolchains are excluded.
The README makes a strong safety claim: no unsafe code anywhere in the codebase. That is the design decision that shapes everything else here. Avoiding unsafe in a concurrent queue usually means leaning on standard synchronisation primitives and accepting some overhead, which is a plausible explanation for why spin is offered as an opt-in rather than a default.
Installing Flume and sending your first message
The README gives the dependency line for Cargo.toml, written with a version placeholder:
flume = "x.y"If you want to drop the default features, the README shows this form, which keeps async and select but disables eventual-fairness along with anything else not listed:
flume = { version = "x.y", default-features = false, features = ["async", "select"] }The README's own example is a complete program. It creates an unbounded channel, moves the sender into a spawned thread, sends 0 through 9, and sums the receiver iterator on the main thread:
use std::thread;
fn main() {
println!("Hello, world!");
let (tx, rx) = flume::unbounded();
thread::spawn(move || {
(0..10).for_each(|i| {
tx.send(i).unwrap();
})
});
let received: u32 = rx.iter().sum();
assert_eq!((0..10).sum::<u32>(), received);
}Run it with cargo run. The assertion should pass, and the program should exit once the sender is dropped. If you switch to a bounded constructor, sends block once the buffer fills, so the same code can deadlock if the producer outruns a consumer that never runs. The repository also ships examples/simple.rs, examples/async.rs, examples/select.rs and examples/perf.rs if you want runnable starting points for the async and select paths.
The maintenance status is the real constraint
The README states plainly that Flume is in casual maintenance mode: critical security and bug fixes continue, heavy feature development has stopped, and new features are welcome as PRs that the maintainer will review when time allows. The repository carries the Casual Maintenance Intended badge. The last push to the default branch was on 2026-08-07, so the project is not abandoned, but the README's own framing is the thing to plan around.
For a channel library this is a smaller problem than it would be elsewhere. The README argues the crate is largely feature-complete, and the API surface it documents is narrow: queues, send and receive variants, timeouts, select, async. A queue that does what you need and receives security fixes is usable for a long time.
The risk shows up in two places. First, if you find a bug that is not a security issue, the fix depends on maintainer availability, and the README does not promise a timeline. Second, if your project needs a feature that does not exist yet, you are writing it yourself and carrying a fork until it lands. Neither is disqualifying, but both should be priced in before you build a large system on top of it.
Where Flume is the wrong choice
If your workload is single-consumer, Flume is more than you need. std::sync::mpsc has no extra dependency, and the README's own framing of Flume as a drop-in replacement means the migration is easy in both directions. Adding a crate for a queue that one thread reads is dependency weight for no semantic gain.
The README's performance claim is also weaker than the tagline suggests. It says Flume is always faster than std::sync::mpsc and sometimes faster than crossbeam-channel, then immediately tells readers not to take its word for it, pointing at the crossbeam-channel benchmark suite and a graph measured on an AMD Ryzen 7 3700x running Linux kernel 5.11.2 with the bfq scheduler. That is one machine, one kernel and one scheduler, and the README does not publish a broader matrix. If channel throughput is the deciding factor for your architecture, you need to benchmark your own workload rather than read the graph.
The no-unsafe guarantee is another trade-off. It is a genuine safety property, and it is also the reason the spin feature exists as an opt-in experiment. If you need the last few percent of throughput on a specific platform, the README does not promise that spin will deliver it, only that it may.
How Flume differs from crossbeam-channel
crossbeam-channel is the obvious comparison, and the repository itself makes it: the benchmark suite used for the README graph comes from crossbeam-channel, and crossbeam-channel is listed as a dev-dependency for the benchmarks. Both are MPMC channels for Rust with bounded and unbounded variants.
The difference the README draws is in implementation posture rather than API. Flume claims no unsafe code anywhere in the codebase. crossbeam-channel's design is not described in this material, so the comparison stops there rather than becoming a claim about which is safer in practice.
The second difference is feature gating. Flume ships its async support, select interface and fairness randomisation as Cargo features, with async, select and eventual-fairness on by default, and lets you strip them with default-features = false. That granularity is a concrete reason to pick Flume if you want a blocking-only channel without pulling in futures-core and futures-sink. The README also notes that Flume's select interface is select-like rather than an exact match for crossbeam's, and that the eventual-fairness feature exists specifically to keep the Selector from biasing some events over others.
Licence and what upgrading costs
Flume is dual-licensed under Apache-2.0 and MIT, and Cargo.toml declares license = "MIT OR Apache-2.0". The repository carries LICENSE-APACHE and LICENSE-MIT at the top level. That is the same permissive pairing used across much of the Rust ecosystem, and it means you choose which terms apply to your use. This is a description of what the repository states, not legal advice; if your organisation has a policy on dual-licensed dependencies, run it past whoever owns that policy.
The upgrade story is the maintenance story. Because heavy feature development has stopped, there is no roadmap of pending breaking changes to plan around, and the README does not document a deprecation or migration policy. The cost you carry is the opposite of churn: the API is stable because it is not moving. The practical risk is a fix you need arriving slowly, and the mitigation is being able to patch the crate yourself. The repository has a CHANGELOG.md at the top level, so version history is at least recorded in-tree rather than only in release notes.
Editorial conclusion
Adopt Flume if you need MPMC semantics, a Send + Sync + Clone sender and receiver, or async mixing on top of a codebase already shaped like std::sync::mpsc. Do not adopt it expecting new features: the README states that heavy feature development has stopped and only critical security and bug fixes continue, so anything you need beyond the current API has to come from your own PR. Before committing, check the feature flags you actually rely on, because async, select and eventual-fairness are on by default and can be turned off with default-features = false.
Frequently asked questions
Is Flume still maintained?
The README states that Flume is in casual maintenance mode: it continues to receive critical security and bug fixes, but heavy feature development has stopped. The last push to the default branch was on 2026-08-07.
How do I install Flume in a Rust project?
The README says to place flume = "x.y" under the [dependencies] section in your Cargo.toml. To drop default features, the README shows flume = { version = "x.y", default-features = false, features = ["async", "select"] }.
What is the difference between Flume and std::sync::mpsc?
Flume supports multiple consumers, while the standard library channel is single-consumer. The README describes Flume as a drop-in replacement for std::sync::mpsc and adds MPMC support, send timeouts and deadlines, an async API, and a select-like interface.
Does Flume contain unsafe code?
The README states that there is no unsafe code anywhere in the codebase.
Which Cargo features does Flume enable by default?
Cargo.toml sets default = ["async", "select", "eventual-fairness"]. The spin feature is opt-in and is not enabled by default.
Official sources
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.
[](https://hysenlabs.com/projects/zesterer-flume)