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.
SQLx’s SQLite driver wraps the libsqlite3 C library via libsqlite3-sys. Unlike the PostgreSQL and MySQL drivers, it is not pure Rust — SQLite has no async-native client protocol, so a background worker thread bridges the blocking SQLite API to the async executor. The driver supports in-memory databases, WAL mode, custom PRAGMAs, foreign key enforcement, and optional extension loading.
Feature flags
Two mutually exclusive base feature flags control how libsqlite3 is linked:
| Feature | Behaviour |
|---|
sqlite | Bundles and statically links the SQLite amalgamation. No system SQLite required. (recommended) |
sqlite-unbundled | Links against the system-installed libsqlite3. Version 3.20.0 or newer recommended. May use bindgen at build time. |
[dependencies]
# Bundled SQLite (most common)
sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite"] }
# System SQLite
sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite-unbundled"] }
The sqlite feature also enables sqlite-load-extension and sqlite-unlock-notify automatically.
SQLx uses #![deny(unsafe_code)] globally, but downgrade this to #![allow(unsafe_code)] on the sqlx::sqlite module because the SQLite C API requires unsafe. The rest of SQLx remains fully safe.
Additional SQLite features
| Feature | What it enables |
|---|
sqlite-load-extension | SqliteConnectOptions::extension() for loading .so/.dll extensions |
sqlite-preupdate-hook | sqlite3_preupdate_hook API (requires sqlite-bundled or a SQLite build with SQLITE_ENABLE_PREUPDATE_HOOK) |
sqlite-deserialize | SqliteConnection::serialize() / ::deserialize() in-memory serialization |
regexp | Registers a REGEXP SQL function backed by the regex crate |
Connection URLs
| URL | Result |
|---|
sqlite::memory: | Unnamed in-memory database (destroyed when the connection closes) |
sqlite:data.db | File data.db in the current directory |
sqlite://data.db | File data.db in the current directory |
sqlite:///data.db | Absolute path /data.db |
sqlite://data.db?mode=ro | Read-only access to data.db |
use sqlx::SqlitePool;
// In-memory database
let pool = SqlitePool::connect("sqlite::memory:").await?;
// File-based database
let pool = SqlitePool::connect("sqlite://app.db").await?;
SqliteConnectOptions
SqliteConnectOptions exposes fine-grained control over connection behaviour. It also implements FromStr, so you can parse a URL string and then apply additional configuration.
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePool};
use std::str::FromStr;
let opts = SqliteConnectOptions::from_str("sqlite://app.db")?
.create_if_missing(true)
.journal_mode(SqliteJournalMode::Wal)
.foreign_keys(true);
let pool = SqlitePool::connect_with(opts).await?;
Key options
| Option / method | Default | Description |
|---|
filename | :memory: | Path to the database file |
in_memory | false | Open a named or anonymous in-memory database |
create_if_missing | false | Create the file if it does not exist |
read_only | false | Open in read-only mode |
foreign_keys | ON | Enforce foreign key constraints (SQLx default; SQLite default is OFF) |
journal_mode | None (SQLite default: DELETE) | Journal mode; WAL is recommended for concurrent read workloads |
synchronous | FULL | Fsync policy; NORMAL is sufficient in WAL mode |
busy_timeout | 5s | How long to wait on a locked database before returning SQLITE_BUSY |
statement_cache_capacity | 100 | LRU prepared-statement cache size per connection |
shared_cache | false | Enable SQLite shared cache mode |
immutable | false | Signal SQLite that the file is on read-only media (disables locking) |
optimize_on_close | Disabled | Run PRAGMA optimize; before closing each connection |
In-memory databases
Each in-memory database is private to a single connection by default. To share one in-memory database across a pool, use a named in-memory URI with shared cache, or build a pool capped to a single connection:
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
// Single-connection pool keeps the same in-memory database alive
let pool = SqlitePoolOptions::new()
.max_connections(1)
.connect("sqlite::memory:")
.await?;
If you use max_connections > 1 with sqlite::memory:, each connection gets its own independent database. Schema changes made on one connection will not be visible to others.
WAL mode
Write-Ahead Logging (WAL) mode significantly improves concurrent read performance because readers do not block writers and writers do not block readers. It is the recommended journal mode for most applications.
WAL mode is a permanent, per-file setting. Once a database file is opened in WAL mode it retains that setting across all future connections. SQLx intentionally does not set a journal_mode by default to avoid unintentionally changing a database into or out of WAL mode (which requires an exclusive lock).
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqliteSynchronous};
use std::str::FromStr;
let opts = SqliteConnectOptions::from_str("sqlite://app.db")?
.create_if_missing(true)
.journal_mode(SqliteJournalMode::Wal)
// NORMAL is safe and faster than FULL in WAL mode
.synchronous(SqliteSynchronous::Normal);
All databases created by sqlx-cli (e.g. via sqlx migrate run) are created in WAL mode. If you manage database files outside of SQLx, set WAL mode manually the first time you open a new database.
Custom PRAGMAs
Any SQLite PRAGMA can be set at connection time using .pragma():
use sqlx::sqlite::SqliteConnectOptions;
use std::str::FromStr;
let opts = SqliteConnectOptions::from_str("sqlite://app.db")?
.pragma("cache_size", "-65536") // 64 MiB page cache
.pragma("mmap_size", "268435456"); // 256 MiB memory-mapped I/O
Loading extensions
Enable the sqlite-load-extension feature, then call .extension() inside an unsafe block. Extension loading is automatically disabled before connect() returns.
use sqlx::sqlite::SqliteConnectOptions;
use std::str::FromStr;
let opts = SqliteConnectOptions::from_str("sqlite://app.db")?;
// SAFETY: only load extensions you trust
let opts = unsafe {
opts.extension("mod_spatialite")
.extension("vsv")
};
let pool = sqlx::SqlitePool::connect_with(opts).await?;
Loading extensions causes arbitrary shared libraries to be executed at runtime. Only load extensions from sources you trust.
Type mapping
SQLite uses a flexible, “type-affinity” system. SQLx maps SQLite’s storage classes to Rust types as follows:
| SQLite affinity / type | Rust type |
|---|
INTEGER | i64, i32, i16, i8, u64, u32, u16, u8, bool |
REAL | f64, f32 |
TEXT | String, &str |
BLOB | Vec<u8>, &[u8] |
TEXT (ISO 8601) | chrono::NaiveDateTime / NaiveDate / NaiveTime (feature: chrono) |
TEXT (RFC 3339) | chrono::DateTime<Utc> (feature: chrono) |
TEXT (UUID) | uuid::Uuid (feature: uuid) |
TEXT / BLOB (JSON) | serde_json::Value (feature: json) |
SQLite stores BOOLEAN as an integer (0 or 1). SQLx maps this transparently; bind a Rust bool and it will be encoded as 0 or 1.