What it is
SQLx is an async, pure-Rust SQL toolkit that verifies your queries against a real database at compile time, without being an ORM.
Use the query! macros for compile-time checked SQL, or the unchecked functions for dynamic queries. Migrations are managed by sqlx-cli.
Installation
cargo add sqlx --features runtime-tokio,postgres,macrosGetting started
The smallest useful thing you can do with it, and what each part means.
rust
// DATABASE_URL must be set at build time for these macros.
let book = sqlx::query_as!(
Book,
"SELECT id, title, year FROM books WHERE id = $1",
id
)
.fetch_optional(&pool)
.await?;
// Misspell a column and this fails to COMPILE, not at runtime:
// error: column "titel" does not existrust
let pool = sqlx::postgres::PgPoolOptions::new()
.max_connections(20)
.acquire_timeout(Duration::from_secs(5))
.connect(&database_url)
.await?;
let id: i64 = sqlx::query_scalar!(
"INSERT INTO books (title, year) VALUES ($1, $2) RETURNING id",
title, year
)
.fetch_one(&pool)
.await?;Advanced usage
Where the library earns its place over a simpler alternative.
rust
let mut tx = pool.begin().await?;
sqlx::query!("UPDATE stock SET quantity = quantity - $1 WHERE sku = $2", qty, sku)
.execute(&mut *tx)
.await?;
sqlx::query!("INSERT INTO orders (sku, qty) VALUES ($1, $2)", sku, qty)
.execute(&mut *tx)
.await?;
tx.commit().await?; // dropping without commit rolls back
// For CI without a database:
// cargo sqlx prepare -> writes .sqlx/ query metadata
// SQLX_OFFLINE=true cargo buildErrors and fixes
The failures you are most likely to hit, and what actually resolves them.
- set DATABASE_URL to use query macros
- The macros need a database at build time. Set the variable, or run cargo sqlx prepare and build with SQLX_OFFLINE=true.
- error occurred while decoding column
- The Rust type does not match the SQL type — commonly i32 against BIGINT, or a non-Option field against a nullable column.
Best practices
- Commit the .sqlx metadata and build with SQLX_OFFLINE in CI.
- Prefer query_as! over query_as — only the macro is verified.
- Set acquire_timeout on the pool so a saturated database fails fast rather than hanging.
- Use transactions for multi-statement invariants; a dropped transaction rolls back automatically.
Background
Why it exists, and what it was reacting to.
SQLx's distinguishing feature is compile-time verification: the macros connect to your development database during cargo build and check that the SQL parses, the columns exist and the Rust types match.
