ECO002-async-runtime-coupling
Dimension: ecosystem
Default severity: Low
Languages: Rust (project-level)
CWE: (none)
What it detects
Fires when [dependencies] contains tokio and none of the following runtime-agnostic alternatives are present: async-std, smol, futures, async-trait.
Why it matters
A hard tokio dependency forces all downstream consumers to also depend on tokio, even if they prefer async-std or smol. For library crates this can cause runtime conflicts and limits adoption.
Heuristic limitations
cfg(…)-gated runtime selection is not detected. A project that feature-gatestokioas an optional executor will still trigger this rule.- Dev-dependencies are not checked. If
tokiois only in[dev-dependencies], the rule is silent. - The presence of
futuresorasync-traitis used as a proxy for runtime-agnostic design — this may produce false-positives if those crates are used for unrelated reasons.
Always review findings manually before acting on them.
Example — flagged
[dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
serde = "1"
Example — not flagged
[dependencies]
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
futures = "0.3" # runtime-agnostic async traits
Fix guidance
- For library crates: abstract the executor behind a feature flag:
[features]tokio-runtime = ["tokio"]async-std-runtime = ["async-std"]
- Use the
futurescrate for executor-agnosticAsyncRead,AsyncWrite, andStreamtraits.
Suppression
# Cargo.toml
# zuit: ignore ECO002-async-runtime-coupling
tokio = { version = "1", features = ["rt-multi-thread"] }