Quickstart
Install DBLift, write one SQL file, preview the statements, then apply them. OSS commands only. About five minutes if a database is already running.
Prefer a tutorial without a database server? Follow Python database migrations with SQL and Python files on SQLite, including checksum validation and undo.
1. Install
Python 3.11+. Quote the extra in zsh — square brackets are glob characters.
$ pip install "dblift[postgresql]"$ dblift --version
2. Configure
A URL is enough for this walkthrough. Commands below assume this variable is set.
Need Postgres? This container matches the sample URL.
$ docker run --name dblift-pg -e POSTGRES_USER=user -e POSTGRES_PASSWORD=password -e POSTGRES_DB=mydb -p 5432:5432 -d postgres:16
$ export DBLIFT_DB_URL="postgresql+psycopg://user:password@localhost:5432/mydb"
Replace user, password, and mydb — or create that role and database first.
3. Create the first migration
Start in a project directory that will hold migrations/.
$ mkdir -p my-database-project/migrations && cd my-database-project
Run every dblift command from the directory that contains migrations/.
Filenames are V<version>__<description>.sql. The version is apply order.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE
);4. Validate
Checksums, order, and applied-state. Nothing is written.
$ dblift validate
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Timestamp: 2026-01-15 12:00:00 ┃ ┃ Dblift version: 3.9.0 ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: VALIDATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Connected to database mydb (PostgreSQL) ┃ ┃ Database: mydb ┃ ┃ Schema: public ┃ ┃ Schema Version: <none> ┃ ┃ Database URL: postgresql+psycopg://user:password@localhost:5432/mydb ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ Migration validation passed ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Command VALIDATE completed successfully (Execution time: 12 ms) ┃ ┃ Schema Version: <none> ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
5. Preview the SQL
Nothing is written. Confirm the statements match what you intended.
$ dblift migrate --dry-run --show-sql
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Timestamp: 2026-01-15 12:00:00 ┃
┃ Dblift version: 3.9.0 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: MIGRATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Connected to database mydb (PostgreSQL) ┃
┃ Database: mydb ┃
┃ Schema: public ┃
┃ Schema Version: <none> ┃
┃ Database URL: postgresql+psycopg://user:password@localhost:5432/mydb ┃
┃ Filtering Options: --dry-run --show-sql ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Found 1 pending migration(s)
DRY RUN: Would execute the following migrations:
- V1_0_0__create_users[core].sql
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ - Dry run — 1 migration(s) would be applied ┃
┃ Command MIGRATE completed successfully (Execution time: 12 ms) ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
SQL Statements:
--------------------------------------------------------------------------------
-- V1_0_0__create_users[core].sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE
);
--------------------------------------------------------------------------------
6. Apply
$ dblift migrate
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Timestamp: 2026-01-15 12:00:00 ┃ ┃ Dblift version: 3.9.0 ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: MIGRATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Connected to database mydb (PostgreSQL) ┃ ┃ Database: mydb ┃ ┃ Schema: public ┃ ┃ Schema Version: <none> ┃ ┃ Database URL: postgresql+psycopg://user:password@localhost:5432/mydb ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ Found 1 pending migration(s) Migration lock acquired successfully ⠋ Migrating 0/1 0:00:00 Statement executed successfully ⠋ Migrating 0/1 0:00:00 Migration V1_0_0__create_users[core].sql executed successfully in 0ms ⠋ Migrating 0/1 0:00:00 Successfully applied migration V1_0_0__create_users[core].sql ⠋ Migrating 0/1 0:00:00 V1_0_0__create_users.sql ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/1 0:00:00 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Command MIGRATE completed successfully (Execution time: 12 ms) ┃ ┃ Schema Version: 1.0.0 ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
7. Check state
$ dblift info
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Timestamp: 2026-01-15 12:00:00 ┃ ┃ Dblift version: 3.9.0 ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: INFO ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Connected to database mydb (PostgreSQL) ┃ ┃ Database: mydb ┃ ┃ Schema: public ┃ ┃ Schema Version: 1.0.0 ┃ ┃ Database URL: postgresql+psycopg://user:password@localhost:5432/mydb ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ === Migration Summary === Total Migrations: 1 Applied Migrations: 1 Pending Migrations: 0 Failed Migrations: 0 ========================= ╭────────────┬─────────┬──────────────┬──────┬─────────────────────┬──────────────┬─────────┬───────────┬──────────╮ │ Category │ Version │ Description │ Type │ Installed On │ Installed By │ State │ Exec Time │ Undoable │ ├────────────┼─────────┼──────────────┼──────┼─────────────────────┼──────────────┼─────────┼───────────┼──────────┤ │ Versioned │ 1.0.0 │ create_users │ SQL │ 2026-01-15 12:00:00 │ you │ Success │ 1ms │ Yes │ ╰────────────┴─────────┴──────────────┴──────┴─────────────────────┴──────────────┴─────────┴───────────┴──────────╯ Total migrations: 1 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Command INFO completed successfully (Execution time: 12 ms) ┃ ┃ Schema Version: 1.0.0 ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
8. Make a second change
Add migrations/V1_1_0__users_created_at.sql, preview, then apply. Only the new file runs.
ALTER TABLE users ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT now();
$ dblift migrate --dry-run --show-sql$ dblift migrate
Optional reversal: pair the file with U1_1_0__drop_created_at.sql, then dblift undo --target-version 1.0.0. See the undo model.