diesel_async

An async extension for Diesel that adds fully asynchronous query execution to Rust's type-safe ORM, with native PostgreSQL, MySQL, and SQLite connections.

Library
Cargo
v0.9.2
824stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
81/100Excellent
Development Activity80
Maintenance80
Community68
Maturity56
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
83/100Excellent
Architecture88
Code Quality87
Innovation90
Learning Curve65

diesel-async extends Diesel, Rust’s compile-time-checked ORM and query builder, with async counterparts to its core traits: RunQueryDsl, Connection, and UpdateAndFetchResults. Rather than replacing Diesel, it is designed to sit alongside it — you keep writing the same table! macros, derives, and query DSL, and only swap the methods that actually perform I/O (.load(), .execute(), .get_result(), transactions) for their async equivalents.

It ships three connection implementations: AsyncPgConnection (backed by tokio-postgres, with pipelining support), AsyncMysqlConnection (backed by mysql_async), and a SyncConnectionWrapper that lets Diesel’s synchronous SQLite backend be driven from async code via a dedicated worker thread. Built-in adapters are provided for the bb8, deadpool, and mobc connection-pooling crates, plus optional support for running Diesel migrations asynchronously and for wrapping an async connection back into a sync diesel::Connection where needed.

What You Get

  • Async RunQueryDsl - drop-in async versions of .load(), .execute(), .get_result(), .get_results(), and .load_stream() for streaming query results as they arrive
  • Three connection backends - AsyncPgConnection (tokio-postgres, with query pipelining), AsyncMysqlConnection (mysql_async), and SyncConnectionWrapper for SQLite
  • Async transactions with savepoint support - .transaction() closures that automatically nest into savepoints, plus .begin_test_transaction() and .test_transaction() for tests
  • Connection pool adapters - ready-made managers for bb8, deadpool, and mobc, selected via Cargo feature flags
  • Async migrations - AsyncMigrationHarness runs diesel_migrations migration sets against an async connection
  • Sync/async bridging - AsyncConnectionWrapper lets an async connection type be driven from synchronous Diesel code when needed

Common Use Cases

  • Tokio-based web services - Axum, Actix, or Tonic services that query Postgres or MySQL without spawning blocking tasks for every database call
  • Streaming large result sets - processing rows via .load_stream() as they’re read off the wire instead of buffering the full query result in memory
  • Pooled connections in async servers - wiring AsyncPgConnection or AsyncMysqlConnection into bb8/deadpool/mobc pools shared across request handlers
  • Async migration runners - applying Diesel migrations from an async startup path (e.g. before a service accepts traffic) without a separate sync entry point
  • Incremental SQLite adoption in async apps - using SyncConnectionWrapper to call Diesel’s SQLite backend from async code without a full rewrite

Under The Hood

Architecture diesel-async is a trait-mirroring extension layer over Diesel rather than a standalone ORM: AsyncConnectionCore and AsyncConnection (src/lib.rs) redeclare Diesel’s Connection trait surface with impl Future-returning methods, and each backend module (src/pg/mod.rs, src/mysql/mod.rs, src/sync_connection_wrapper/mod.rs) implements those traits against a specific async driver — tokio-postgres for Postgres, mysql_async for MySQL, and a background worker thread wrapping Diesel’s own synchronous SQLite connection. Query execution flows through src/run_query_dsl/mod.rs, which reimplements Diesel’s RunQueryDsl methods (load, execute, get_result, load_stream) in terms of AsyncConnectionCore::load/execute_returning_count, keeping the query-building code (table!, filters, joins) entirely reused from upstream Diesel. Transactions and their savepoint nesting are centralized in src/transaction_manager.rs via the shared AnsiTransactionManager, and pooling is abstracted in src/pooled_connection/mod.rs with concrete adapters in bb8.rs, deadpool.rs, and mobc.rs gated behind Cargo features. Swapping the core AsyncConnection trait would ripple through every backend module and the pool adapters simultaneously, since they all implement against the same trait contract.

Tech Stack The crate is pure Rust on the 2021 edition, built against diesel ~2.3 with the i-implement-a-third-party-backend-and-opt-into-breaking-changes opt-in feature that lets it plug into Diesel’s backend abstraction. Async I/O is layered on tokio plus futures-core/futures-util for the Stream/Future plumbing; Postgres support comes from tokio-postgres, MySQL from mysql_async/mysql_common. Pooling is optional and pluggable via bb8, deadpool, or mobc, each behind its own Cargo feature, and diesel_migrations is pulled in only when the migrations feature is enabled. The repository is a Cargo workspace that also builds four example crates (postgres pipelining, pooled-with-rustls, migrations-with-rustls, and a sync-wrapper example) so the documented patterns are compiled and checked, not just prose.

Code Quality The project has a dedicated tests/ integration suite (tests/lib.rs plus per-topic modules: transactions, pooling, migrations, notifications, type_check, custom_types, multiconnection) that CI runs across the postgres, mysql, and sqlite backend features and across Ubuntu, macOS (Intel and ARM), and Windows. A separate CI job runs cargo clippy --all --all-features and cargo fmt --all -- --check on every PR and merge-group run. The crate enables #![warn(missing_docs, clippy::cast_possible_wrap, clippy::cast_possible_truncation, clippy::cast_sign_loss)], and public APIs carry extensive rustdoc with runnable doctests (src/lib.rs, src/pg/mod.rs). There is no separate CONTRIBUTING.md or docs/ directory — guidance lives in the README and inline rustdoc instead.

API Design The library’s central design goal is that call sites barely change from sync Diesel: the same table!-generated query DSL is reused unmodified, and only the terminal execution methods (.load(), .execute(), .get_result()) gain an .await. Feature flags (postgres, mysql, sqlite, bb8, deadpool, mobc, migrations, r2d2) let consumers pull in exactly one backend and one pool implementation with zero unused dependencies compiled in — none are enabled by default. Getting started requires little boilerplate beyond picking features and calling AsyncPgConnection::establish(url).await, and the transaction closures accept ordinary async closures rather than a bespoke transaction-scoped type.

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