async-trait (Rust)
Proc-macro crate that enables async fn in Rust traits — a feature that was missing from stable Rust until the Return Position Impl Trait (RPITIT) stabilization. async-trait transforms async fn trait methods into box-pinned futures, enabling async methods in trait definitions and implementations. Widely used in Rust async codebases where trait polymorphism and async are both needed. Note: largely superseded by native async fn in traits stabilized in Rust 1.75.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Local proc-macro — no network calls. Proc-macros run at compile time — only code from trusted crates should be used as proc-macros.
⚡ Reliability
Best When
You need async methods in Rust traits on Rust < 1.75, or need dyn-compatible async traits (Box<dyn Trait>) even on newer Rust versions.
Avoid When
You're on Rust 1.75+ and don't need dyn trait objects — native async fn in traits works without the macro and without boxing.
Use Cases
- • Define async Rust traits for agent service interfaces — async fn execute(&self, task: Task) -> Result<Output> in trait definitions for polymorphic agent services
- • Implement trait-based dependency injection in async Rust agent code — swap real and mock implementations at the trait level
- • Create trait objects (Box<dyn ServiceTrait>) for runtime polymorphism in agent code that needs to dispatch to different implementations
- • Build async middleware chains in Rust using async trait objects — compose agent processing pipelines via trait objects
- • Enable async mock implementations of service traits for async testing of Rust agent code
Not For
- • Rust 1.75+ projects with stable async fn in traits — use native Rust async fn in traits without the macro overhead
- • Performance-critical hot paths — async-trait allocates a Box per call due to trait object erasure; use concrete types where possible
- • Simple async functions without trait polymorphism — regular async fn doesn't need async-trait
Interface
Authentication
Local macro library — no external auth or network calls.
Pricing
MIT/Apache 2.0 dual-licensed. Note: becoming less necessary with Rust 1.75+ native async fn in traits.
Agent Metadata
Known Gotchas
- ⚠ async-trait adds Send + 'static bounds to the returned Future by default — methods that capture non-Send values cause compile errors; use #[async_trait(?Send)] for single-threaded code
- ⚠ Box allocation per call is significant overhead for hot paths — profile before adding async-trait to frequently-called agent methods; consider concrete types for performance-critical code
- ⚠ Rust 1.75+ native async fn in traits works for static dispatch but NOT for dyn Trait (trait objects) — still need async-trait or trait_variant for Box<dyn AgentTrait> dynamic dispatch
- ⚠ Method signatures in #[async_trait] implementations must match the trait exactly — lifetime elision differences between trait and impl cause confusing 'method not in trait' errors
- ⚠ Upgrading from async-trait to native async fn in traits requires removing the macro attribute from both trait definition and all implementations — missing one causes mismatched method signature errors
- ⚠ async-trait with self: Arc<Self> receivers enables actor-style patterns but requires explicit Arc cloning before async boundaries — not obvious from the trait definition alone
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for async-trait (Rust).
Scores are editorial opinions as of 2026-03-06.