async-channel

Async multi-producer multi-consumer channel for Rust with bounded and unbounded variants.

Library
Cargo
v2.5.0
942stars
Apache-2.0 OR MIT

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
52/100Fair
Development Activity36
Maintenance24
Community48
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
83/100Excellent
Architecture86
Code Quality88
Innovation74
Learning Curve84

async-channel is a Rust crate providing an asynchronous multi-producer multi-consumer (MPMC) channel, where every message sent is received by exactly one of the existing consumers. It offers both bounded channels with a fixed capacity and unbounded channels that grow as needed, with senders and receivers that can be freely cloned and shared across tasks.

Part of the smol-rs async ecosystem, the crate integrates with any async runtime through futures-based send and receive operations, supports Stream and Sink-style usage, and works in no_std environments. With hundreds of millions of downloads it is one of the most widely used channel primitives in async Rust.

What You Get

  • Bounded and unbounded async MPMC channels via bounded() and unbounded()
  • Cloneable Sender and Receiver halves that can be shared across many tasks
  • Async send/recv futures plus non-blocking try_send and try_recv
  • Stream and Sink integration for use with the futures ecosystem
  • no_std support and runtime-agnostic operation across async executors

Common Use Cases

  • Distributing work items across a pool of async worker tasks
  • Passing messages between concurrent tasks without blocking threads
  • Building backpressure-aware pipelines with bounded capacity
  • Fanning out jobs where each message should be handled once

Under The Hood

Architecture - The whole crate lives in a single ~1,400-line src/lib.rs. Internally it wraps a lock-free concurrent-queue for message storage and uses event-listener-strategy to park and wake tasks waiting to send (on a full bounded queue) or receive (on an empty one). A shared inner channel struct tracks sender and receiver counts so the channel closes automatically when either side is fully dropped; Sender and Receiver are thin cloneable handles over this shared state, with pin-project-lite driving the Send/Recv future state machines and futures-core providing Stream.

Tech Stack - Rust 2021 (MSRV 1.60) with a lean dependency set: concurrent-queue for the buffer, event-listener-strategy for async wakeups, futures-core for the Stream trait, and pin-project-lite for safe pin projection. Optional portable-atomic and portable-atomic-util dependencies plus a no-default std feature enable no_std and constrained-platform builds; dev-dependencies include futures-lite and wasm-bindgen-test for testing, including on wasm targets.

Code Quality - As a foundational smol-rs crate the code is carefully written and well documented, with dedicated integration tests for bounded and unbounded behavior (tests/bounded.rs, tests/unbounded.rs) covering capacity, closing, and concurrency, plus a maintained CHANGELOG and CI. It is mature and stable, receiving periodic correctness and dependency updates rather than large feature churn.

API Design - The public API is small and idiomatic: bounded(cap) or unbounded() return a (Sender, Receiver) pair; you await sender.send(msg) and receiver.recv(), or use try_send/try_recv for non-blocking paths, and iterate the receiver as a Stream. Cloning either half to add producers or consumers is trivial, and the runtime-agnostic future-based design means it drops into any executor with no setup, keeping the learning curve low for anyone familiar with channels.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search