dtolnay

dtolnay/async-trait

Rust Apache-2.0 Dev Tools Single maintainer risk

Type erasure for async trait methods

2.2k stars
100 forks
recent
GitHub +3 / week

2.2k

Stars

100

Forks

10

Open issues

19

Contributors

0.1.89 14 Aug 2025

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...

Dev Tools Library Discovery value: 3/10
Documentation 8/10
Activity 9/10
Community 8/10
Code quality 8/10

Inferred from signals mentioned in the README (tests, CI, type safety) — not a review of the actual code.

Overall score 9/10

AI's overall editorial judgment — not an average of the bars above, can weigh other factors too.

rust async-programming trait-macros type-erasure dynamic-dispatch
Actively maintained Well documented Popular Niche/specialized use case Production ready
Deep Analysis · Based on README and public signals
1w ago

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.

Origin

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.

Growth

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.

In production

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.

Code analysis
Architecture

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.

Tests

Not documented in README. CI badge present (GitHub Actions), suggesting automated testing, but test structure not described.

Maintenance

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.

Honest verdict

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

Risks
  • 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.
Prediction

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.

0 found this helpful

Newsletter

Get analyses like this every Monday

Free weekly digest of the most interesting open-source discoveries.

Languages

Rust
100%

Information

Language
Rust
License
Apache-2.0
Last updated
2w ago
Created
85mo ago
Analyzed with
anthropic/claude-haiku-4-5

Stars over time

Loading…

Contributors over time

Top 100 contributors only — repos with more will plateau at 100.

Loading…

Similar repos

dtolnay

dtolnay/typetag

Typetag enables serialization and deserialization of trait objects in Rust via...

1.5k Rust Dev Tools
dtolnay

dtolnay/syn

Syn is a mature parser library for Rust source code, specifically designed for...

3.3k Rust Dev Tools
JelteF

JelteF/derive_more

derive_more is a Rust procedural macro library that eliminates boilerplate by...

2.1k Rust Dev Tools
dtolnay

dtolnay/thiserror

thiserror is a derive macro for implementing Rust's std::error::Error trait...

5.5k Rust Dev Tools
dtolnay

dtolnay/case-studies

A specialized educational repository that dissects tricky Rust code patterns...

2k Rust Education
vs. alternatives
Native async fn in traits (Rust 1.75+)

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.

Manual Future boxing

Developers can manually write out Pin<Box<dyn Future>> signatures; async-trait eliminates boilerplate and improves readability.

Object-safe trait patterns (delegation, enums)

Alternative designs avoid trait objects entirely via enum dispatch or delegation. async-trait enables object-safe async traits directly.

futures::future::BoxFuture (via futures crate)

Lower-level primitive; async-trait builds a usable macro interface on top of the same boxed-future pattern.

GAT (Generic Associated Types) patterns

GATs enable lifetime-erased associated future types but require Rust nightly and more complex trait definitions. async-trait is simpler for stable Rust.