Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/launchbadge/sqlx/llms.txt

Use this file to discover all available pages before exploring further.

The Any driver is a thin runtime-dispatch layer that routes connections to the correct underlying driver based on the URL scheme. It lets you write code that works against AnyPool and AnyConnection without specifying a concrete database type, with the actual backend chosen at startup from environment variables or configuration. This is useful for libraries that must support multiple databases, or for codebases that test against SQLite locally and deploy against PostgreSQL in production.

Feature flag

Enable the any feature alongside at least one concrete driver:
[dependencies]
# Any with PostgreSQL and SQLite support
sqlx = { version = "0.8", features = [
    "runtime-tokio",
    "tls-rustls-ring-webpki",
    "any",
    "postgres",
    "sqlite",
] }
any is part of SQLx’s default feature set, so if you are not overriding default-features it is already enabled.

Installing drivers

Before creating any AnyPool or AnyConnection, you must register the set of available drivers exactly once at process startup by calling sqlx::any::install_default_drivers(). Without this call, any attempt to open a connection will panic.
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // Must be called before any AnyPool or AnyConnection is created.
    // Safe to call multiple times; only the first call has an effect.
    sqlx::any::install_default_drivers();

    let pool = sqlx::AnyPool::connect(&std::env::var("DATABASE_URL")?).await?;

    // ...
    Ok(())
}
install_default_drivers registers every driver that was compiled in (controlled by feature flags). If you need fine-grained control over which drivers are available, use the lower-level sqlx::any::install_drivers instead.
Calling install_default_drivers after install_drivers has already been called (not via install_default_drivers) will panic. Call one or the other, not both.

URL-based routing

The Any driver selects the underlying driver from the URL scheme:
URL schemeDriver used
postgres:// or postgresql://PostgreSQL driver
mysql://MySQL / MariaDB driver
sqlite:SQLite driver
use sqlx::AnyPool;

// Connects to PostgreSQL
let pg_pool = AnyPool::connect("postgres://user:pass@localhost/mydb").await?;

// Connects to MySQL
let mysql_pool = AnyPool::connect("mysql://root:pass@localhost/mydb").await?;

// Connects to an in-memory SQLite database
let sqlite_pool = AnyPool::connect("sqlite::memory:").await?;
At runtime, all three pools have the same type (AnyPool) and expose the same API, while the work is delegated to the appropriate concrete driver.

Core types

TypeDescription
AnyPoolAlias for Pool<Any>. Manages a pool of AnyConnections.
AnyConnectionA single database-agnostic connection.
AnyRowA row returned by an Any query.
AnyConnectOptionsParsed connection options; the scheme determines the driver.
AnyPoolOptionsAlias for PoolOptions<Any>.

Writing database-agnostic code

Use AnyPool as the connection source throughout your application layer:
use sqlx::AnyPool;

async fn count_users(pool: &AnyPool) -> Result<i64, sqlx::Error> {
    let (count,): (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users")
        .fetch_one(pool)
        .await?;
    Ok(count)
}
The same function works against PostgreSQL, MySQL, or SQLite without modification.
sqlx::any::install_default_drivers();
let pool = AnyPool::connect("postgres://user:pass@prod-host/appdb").await?;
let n = count_users(&pool).await?;

Testing with SQLite, deploying on PostgreSQL

A common pattern is to run fast integration tests against an in-memory SQLite database and deploy against PostgreSQL:
#[cfg(test)]
async fn test_pool() -> sqlx::AnyPool {
    sqlx::any::install_default_drivers();
    let pool = sqlx::AnyPool::connect("sqlite::memory:").await.unwrap();
    sqlx::migrate!("./migrations").run(&pool).await.unwrap();
    pool
}

#[tokio::test]
async fn test_insert_user() {
    let pool = test_pool().await;
    // Run your tests against the AnyPool
}
For migrations to work with both backends, write SQL that is valid on all targeted databases. Avoid PostgreSQL-specific syntax (e.g. SERIAL, RETURNING) or MySQL-specific syntax (e.g. AUTO_INCREMENT) in shared migration files.

Limitations

The Any driver is a useful abstraction, but it has inherent constraints compared to using a concrete driver directly:

No driver-specific types

PostgreSQL-specific types (JSONB, arrays, ranges, custom enums), MySQL-specific types, and SQLite pragmas are not accessible through the Any API. Use the concrete driver when you need these features.

No driver-specific extensions

PgListener (LISTEN/NOTIFY), advisory locks, PostgreSQL COPY, and other driver-specific APIs are not available via AnyPool. Acquire a typed connection when needed.

SQL dialect differences

Bind parameter syntax differs: PostgreSQL uses $1, MySQL uses ?, and SQLite accepts both. The Any driver does not normalise SQL; you must write queries that are valid in all target databases.

compile-time macros unsupported

The query! and query_as! macros require a concrete database URL at compile time and do not work with AnyPool. Use the runtime sqlx::query() API instead.
Third-party drivers (e.g. sqlx-exasol) can be registered with sqlx::any::install_drivers and used through AnyPool as long as they implement the AnyDriver trait. Since SQLx 0.7, drivers no longer need to be compiled into the sqlx crate itself.

Build docs developers (and LLMs) love