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.

SQLx includes a first-class migration system that tracks and applies versioned SQL scripts to keep your database schema in sync with your application code. Migrations are plain SQL files stored alongside your source code, and SQLx records which ones have been applied in a _sqlx_migrations table so that only pending scripts are ever executed.

How SQLx migrations work

Every migration is a .sql file with a numeric version prefix. When you run migrations, SQLx reads the _sqlx_migrations table, compares it against the files in your migrations directory, and applies only the scripts that have not yet been recorded. Each applied migration is stored with a SHA-384 checksum; if a previously-applied file changes on disk, SQLx returns an error to prevent silent schema divergence.
Migrations require the migrate feature flag. Add it to your Cargo.toml alongside the relevant database feature:
[dependencies]
sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "migrate"] }

Migration directory structure

By convention, migration files live in a migrations/ directory at the root of your project. SQLx uses the filename to determine version order and description. Files that do not match the expected format are silently ignored.
migrations/
├── 20240101120000_create_users.sql
├── 20240102090000_add_email_index.sql
└── 20240115143000_create_posts.sql
Each filename follows the pattern <VERSION>_<DESCRIPTION>.sql, where <VERSION> is any integer greater than zero. The sqlx migrate add command generates timestamps in YYYYMMDDHHmmss format automatically. For reversible migrations, files come in .up.sql / .down.sql pairs:
migrations/
├── 20240101120000_create_users.up.sql
└── 20240101120000_create_users.down.sql

The migrate! macro

The migrate! macro embeds your migration files directly into the compiled binary at build time. This is the most common way to run migrations in production because it does not require the migrations/ directory to be present at runtime.
use sqlx::postgres::PgPoolOptions;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let pool = PgPoolOptions::new()
        .connect("postgres://localhost/mydb")
        .await?;

    // Embeds migrations from ./migrations relative to CARGO_MANIFEST_DIR
    sqlx::migrate!().run(&pool).await?;

    Ok(())
}
You can pass an explicit path to a different directory:
sqlx::migrate!("db/migrations").run(&pool).await?;
The path is resolved relative to CARGO_MANIFEST_DIR (the directory containing Cargo.toml) at compile time.

Programmatic migration with Migrator

For cases where you need runtime control — such as loading migrations from a path determined at startup — use Migrator::new():
use sqlx::migrate::Migrator;
use std::path::Path;

let migrator = Migrator::new(Path::new("./migrations")).await?;
migrator.run(&pool).await?;
Migrator exposes additional configuration methods:
MethodDescription
set_ignore_missing(true)Ignore applied migrations that are no longer present on disk
set_locking(false)Disable advisory locking (e.g. for CockroachDB)
dangerous_set_table_name(name)Override the _sqlx_migrations tracking table name
Changing the tracking table name with dangerous_set_table_name on a database that already has applied migrations will cause SQLx to lose track of what has run and attempt to re-apply all migrations.

The _sqlx_migrations table

SQLx creates this table automatically on the first migration run. It records the version number, description, type, checksum, and execution timestamp for each applied migration. You should not manually modify this table.
ColumnTypeDescription
versionBIGINTThe numeric version from the filename
descriptionTEXTThe human-readable name from the filename
installed_onTIMESTAMPTZWhen the migration was applied
successBOOLEANWhether the migration completed without error
checksumBYTEASHA-384 hash of the migration SQL
execution_timeBIGINTDuration in nanoseconds

The migrate feature flag

The migration system is gated behind the migrate Cargo feature. Without it, neither sqlx::migrate!() nor sqlx::migrate::Migrator will be available.
[dependencies]
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls-ring-webpki", "postgres", "migrate"] }

Writing migrations

Create migration files with the CLI, run and revert them, and check status.

Offline mode

Cache query metadata so you can build without a live database in CI.

Build docs developers (and LLMs) love