Getting started with DBLift: your first migration in five minutes

No database server, no config file. pip install, three migration files, then info, migrate, validate and undo against a SQLite file. Same files run on PostgreSQL afterwards.

Most migration tutorials start with "first, install PostgreSQL". This one does not. DBLift talks to SQLite out of the box, so you can see the whole loop, apply, verify, roll back, on a file in your project folder. When it clicks, you point the same files at a real server.

Every output block below is copied from a terminal running DBLift 3.10.1, trimmed to the lines that matter: the real thing adds a header box per command and a few more columns. Five minutes, one extra if you type slowly.

Minute one: install and pick a file

pip install dblift
export DBLIFT_DB_URL="sqlite:///./app.db"

SQLite's driver ships with Python, so the bare package is enough. For any other engine you add a driver extra, and that is the only install difference: pip install "dblift[postgresql]".

The database file does not need to exist. DBLift creates it on first contact.

Minute two: three files

Migrations live in a migrations folder next to where you run the command. Three files show the three kinds.

CREATE TABLE accounts (
    id INTEGER PRIMARY KEY,
    email TEXT NOT NULL UNIQUE,
    active INTEGER
);
def migrate(context):
    if context.dry_run:
        return
    context.execute("UPDATE accounts SET active = 1 WHERE active IS NULL")
DROP VIEW IF EXISTS active_accounts;
CREATE VIEW active_accounts AS SELECT id, email FROM accounts WHERE active = 1;
  • V files are versioned. They run once, in version order, and never again.
  • R files are repeatable. They run every time their content changes. Views and functions go here.
  • U files undo a specific version. We add one in a minute.

The double underscore between version and description is mandatory. .sql and .py sit side by side; a Python file just needs a migrate(context) function.

Minute three: look before you run

dblift info
Total Migrations: 3
Applied Migrations: 0
Pending Migrations: 3

│ Category   │ Version │ Description     │ Type   │ State   │ Undoable │
├────────────┼─────────┼─────────────────┼────────┼─────────┼──────────┤
│ Versioned  │ 1       │ create_accounts │ SQL    │ Pending │   Yes    │
│ Versioned  │ 2       │ backfill_active │ Python │ Pending │    No    │
│ Repeatable │         │ active_accounts │ SQL    │ Pending │    No    │

Nothing has touched the database yet. Two things worth a glance: V2 is not undoable, because there is no U2 file, and the repeatable has no version, because it is not supposed to have one.

Minute four: apply

dblift migrate
Found 3 pending migration(s)
Migration lock acquired successfully
Successfully applied migration V1__create_accounts.sql
Successfully applied migration V2__backfill_active.py
Successfully applied migration R__active_accounts.sql
Command MIGRATE completed successfully (Execution time: 95 ms)
Schema Version: 2

Run dblift info again and every row reads Success with a timestamp and your username. That record lives in a table named dblift_schema_history inside app.db, next to your own tables. Run dblift migrate a second time and it finds nothing to do.

Minute five: break it on purpose

Add a comment to the end of the file you already applied, then ask DBLift whether everything still lines up.

echo "-- edited after apply" >> migrations/V1__create_accounts.sql
dblift validate
ERROR: Migration script V1__create_accounts.sql has been modified
       since it was applied.
       Database checksum: 1182080837, Filesystem checksum: 694709856
ERROR: Validation failed. Detected modified migration scripts.
Command VALIDATE failed (Execution time: 10 ms)

This is the whole point of a history table. Every applied file is recorded with a checksum. Edit it afterwards and validate refuses, before any deploy job gets to run it. Fix by reverting the edit, or by shipping the change as a new versioned file. Put dblift validate in CI and this failure happens on the pull request, not in production.

Delete the line you added, then check again:

dblift validate
Migration validation passed

One more minute: go backwards

Undo is opt-in, one companion file per version. Give V2 one:

def migrate(context):
    if context.dry_run:
        return
    context.execute("UPDATE accounts SET active = NULL WHERE active = 1")
dblift undo --target-version 1
Found 1 migration(s) to undo
Successfully undone migration V2__backfill_active.py
Schema Version: 1

dblift info now shows V2 twice: the original row marked Undone, and a fresh Pending row underneath, because the file is still in the folder. dblift migrate applies it again. Undo never deletes history, it appends to it.

Same files, real database

Nothing above was SQLite-specific. To run it against PostgreSQL, install the driver, change the URL, and name the schema. That last part is the only new requirement: SQLite and DuckDB have no schemas, every other engine wants one.

pip install "dblift[postgresql]"
export DBLIFT_DB_URL="postgresql+psycopg://app:secret@localhost:5432/app"
export DBLIFT_DB_SCHEMA="public"
dblift info

The migration files, the commands, and the output are the same. The only line you would change in the SQL is INTEGER PRIMARY KEY, which SQLite treats as auto-increment and PostgreSQL does not.

When the environment variables get old, the same settings go in a dblift.yaml at the project root. The Configuration page has the full list; the Flyway article shows a complete example.

Where this goes next

  • CIdblift/action@v1 installs the package and runs validate or migrate in a GitHub job. The best practices article shows the pinned form.
  • Testspytest-dblift applies your migrations before the test session starts, so tests run against the real schema.
  • Coming from Flyway — keep your files, import the history table, read Flyway for a Python shop.
  • Other engines — MySQL, SQL Server, Oracle, DB2, DuckDB, Cosmos DB, MongoDB and the PostgreSQL-compatible clouds are all a driver extra away. See Database engine coverage.

One housekeeping note: DBLift writes a log file per command into a logs folder in the working directory. Add it to .gitignore along with app.db.

The core commands you used, info, migrate, validate, undo, need no license. Offline SQL review (validate-sql) and release evidence (plan, preflight) are part of the commercial dblift-enterprise distribution; see Pricing when you get there.

DBLift is information technology / developer tools software. Contact: contact@dblift.com.