Type erasure for async trait methods
2.2k
Stars
100
Forks
10
Open issues
19
Contributors
AI Analysis
async-trait is a Rust macro that enables async functions in trait definitions and dynamic trait objects (dyn Trait), solving a gap in Rust's native async trait support as of version 1.75. It is essential for developers building trait-based async abstractions and dynamic dispatch patterns in Rust—particularly valuable for library authors, framework designers, and async runtime users who need flexible trait compositions. It is not for developers who don't use traits or those working with simple...
Inferred from signals mentioned in the README (tests, CI, type safety) — not a review of the actual code.
AI's overall editorial judgment — not an average of the bars above, can weigh other factors too.
Macro-based workaround for using async trait methods with dynamic dispatch in Rust
async-trait is a procedural macro that enables dynamic trait objects (dyn Trait) to work with async methods in Rust. It transforms async fn in traits into boxed futures, addressing a gap in Rust 1.75's async trait stabilization. Widely adopted in the Rust async ecosystem, particularly in libraries requiring trait objects with async behavior. The crate solves a real constraint in the language, not a gap in best practices.
Created July 2019 by David Tolnay as a workaround before native async trait support existed. Remained relevant after Rust 1.75 stabilized async fn in traits (late 2023) because that stabilization did not include dyn-compatibility—a fundamental limitation that likely persists. The crate has remained substantially unchanged since its core solution was established.
Rapid initial growth (2019–2021) as async Rust adoption accelerated and trait objects became common in async library design. Growth plateau around 2021–2022 as the core use case stabilized and the ecosystem settled on patterns. Recent activity minimal but consistent—last push June 2026, indicating ongoing maintenance. Star count (2,160) reflects mature, purpose-built tooling rather than trending adoption.
Adoption not formally verified in README. However, contextual evidence: (1) 2,160 stars on a narrow-purpose crate in mature Rust ecosystem suggests significant adoption; (2) written by David Tolnay, whose other crates (thiserror, anyhow, quote) are foundational; (3) listed on crates.io with download metrics available but not provided here; (4) README examples imply library author audience. No public case studies or adoption stories in README.
Based on README, appears to be a procedural macro that rewrites async fn in trait definitions and implementations into methods returning Pin<Box<dyn Future + Send + 'async_trait>>. Likely uses syn/quote crate ecosystem (implied by Tolnay's design pattern). No unsafe code claimed. Supports generics, lifetimes, associated types, and mixed async/non-async methods. The ?Send variant allows non-Send futures. Implementation strategy is straightforward syntactic transformation rather than compiler plugin.
Not documented in README. CI badge present (GitHub Actions), suggesting automated testing, but test structure not described.
Last push 2026-06-24, 7 days before evaluation date—active maintenance. Issue and PR activity not disclosed in metadata, but regular maintenance commits suggest responsive curation. No major version bump needed since core feature is stable; slow push rate is consistent with feature-complete, well-scoped tooling rather than feature churn.
ADOPT IF: you need dynamic trait objects with async methods on stable Rust and are willing to accept the runtime cost of boxed futures and the macro layer. The crate is mature, well-maintained, and solves a real constraint. AVOID IF: (1) you can restructure your design to avoid trait objects (enum dispatch, generics), (2) you control the call sites and can use generic async fn in traits directly (no dyn), or (3) you need zero-cost abstraction and cannot accept Box allocation overhead. MONITOR IF: Rust's trait object ergonomics or async trait stabilization evolve in ways that reduce the need for this workaround, though such changes appear unlikely in the near term.
Independent dimensions
Mainstream potential
4/10
Technical importance
7/10
Adoption evidence
6/10
- Macro-based expansion can obscure error messages and make debugging trait method signatures harder than native syntax.
- Performance cost of Box allocation and dynamic dispatch is not free; high-frequency calls may show measurable overhead.
- Lifetime elision rules are stricter in async fn than sync fn (as noted in README); users must be explicit, creating friction.
- If Rust ever adds native dyn-safe async trait support, this crate becomes obsolete—though such support would likely be backward compatible.
- Maintenance depends on a single active maintainer (Tolnay); bus factor is a structural risk for infrastructure-level crates.
async-trait will remain stable and necessary for the foreseeable future. Slow maintenance and minimal star growth over recent years reflect maturity and stability, not decline. Unless Rust stabilizes dyn-async-trait support (unlikely before 2027+), this crate will remain a permanent fixture in the async Rust ecosystem. Growth is unlikely; the tool has reached its addressable market.
Newsletter
Get analyses like this every Monday
Free weekly digest of the most interesting open-source discoveries.
Languages
Information
- Language
- Rust
- License
- Apache-2.0
- Last updated
- 2w ago
- Created
- 85mo ago
- Analyzed with
- anthropic/claude-haiku-4-5
Stars over time
Contributors over time
Top 100 contributors only — repos with more will plateau at 100.
Open issues
The `'async_trait` outlives bounds trigger a rustc caching bug, re-proving `Send` once per impl
Can not find 'Box' on no_std environments
Elided lifetimes in function arguments trigger error: lifetime parameters do not match the trait definition
Where to subcribe for updates about `dyn Trait`?
Compile success when generic parameter is possibly not "Send", but compile fail if said parameter is in a tuple
Top contributors
Recent releases
Similar repos
| Repository | Stars | Week Δ | Language | Score | Updated |
|---|---|---|---|---|---|
|
|
2.2k | +3 | Rust | 9/10 | 2w ago |
|
|
1.5k | — | Rust | 8/10 | 2w ago |
|
|
3.3k | — | Rust | 9/10 | 1d ago |
|
|
2.1k | — | Rust | 8/10 | 3w ago |
|
|
5.5k | — | Rust | 9/10 | 2w ago |
|
|
2k | — | Rust | 8/10 | 2w ago |
Rust's native support stabilized async fn in traits but does not support dyn Trait with async methods. async-trait is not a replacement but a complementary workaround for a language limitation.
Developers can manually write out Pin<Box<dyn Future>> signatures; async-trait eliminates boilerplate and improves readability.
Alternative designs avoid trait objects entirely via enum dispatch or delegation. async-trait enables object-safe async traits directly.
Lower-level primitive; async-trait builds a usable macro interface on top of the same boxed-future pattern.
GATs enable lifetime-erased associated future types but require Rust nightly and more complex trait definitions. async-trait is simpler for stable Rust.