Plain SQL migrations for Python. See the exact SQL before it runs.
Get started · Documentation · Coming from Flyway · Adopt an existing database
DBLift applies versioned .sql files to your database and remembers what ran. Same file convention as Flyway (V1__create_users.sql), installed with pip, usable as a CLI or as a Python library. Preview, undo, checksums and locking are part of the open-source package. Apache 2.0.
Try it in 60 seconds
No database server needed — this runs against a local SQLite file.
pip install dblift
mkdir migrations
echo "CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT NOT NULL UNIQUE);" > migrations/V1__create_users.sql
echo "DROP TABLE users;" > migrations/U1__create_users.sql
export DBLIFT_DB_URL="sqlite:///app.db"
dblift migrate --dry-run --show-sql # prints the SQL, applies nothing
dblift migrate # applies V1
dblift info # what ran, when, by whom, and whether it can be undone
dblift undo # runs U1, rolls the last migration back
For a real database, install the driver extra and point the URL at it:
pip install "dblift[postgresql]"
export DBLIFT_DB_URL="postgresql+psycopg://user@localhost:5432/mydb"
export DBLIFT_DB_PASSWORD="..."
Your first migration → · Configuration →
Is this for you?
You run Flyway from a Python project. A JVM, a Docker image or a downloaded tarball, kept patched only to apply SQL files. DBLift reads the same V / R / U file names, and dblift import-flyway copies your flyway_schema_history so every environment keeps its history. What changes is the install line. Move from Flyway →
You apply SQL with a migrate.sh or a home-made migrate.py. It works until two files share a number, someone edits an applied file, a replica starts at the same time, or production turns out to be two migrations behind staging. That script is a migration tool you maintain by accident. Rename the files, run dblift baseline once per existing database, and delete it. Adopt an existing database → · Naming conventions →
You want migrations you can read in a pull request. Not revisions generated from an ORM — the SQL you wrote, reviewed as SQL, run as written. Works next to SQLAlchemy, Django, FastAPI and Flask, or with none of them.
What you get
Everything below ships in the open-source package.
| Preview | migrate --dry-run --show-sql prints every statement that would run. Same for undo. |
| Undo | Pair V3__x.sql with U3__x.sql; dblift undo rolls back one step or to a target version. Undo model → |
| Checksums | dblift validate fails when an applied file was edited, a recorded file is missing, or two files claim the same version. |
| SQL checks | dblift validate-sql reads your migration SQL without connecting and gives each script a verdict, SAFE, REVIEW or UNSAFE, for statements that destroy data, break the deployed application or lock a table. SQL checks → |
| Baseline | Adopt a database that already exists: declare "this one is at version N" and carry on from there. |
| Repeatable migrations | R__views.sql re-runs when its content changes — a home for views, functions, grants and seed data. |
| Locking | A lock table serialises concurrent runs; a second runner waits, then skips what the first one applied. |
| Python migrations | V4__backfill.py when a change needs logic. Python migrations → |
| A Python API | Sync and async clients, events and callbacks — run migrations from your app or your tests, not only from a shell. |
| Transactions | A migration that fails part-way is rolled back where the engine supports transactional DDL. |
| No lock-in | Your migrations stay plain .sql files in your repository. |
Ordering: DBLift applies out-of-order migrations by default — if
V3is applied and a teammate'sV2merges later,V2still runs. This is the opposite of Flyway's default. Use--strictorstrict_mode: trueto enforce version order. Versioning →
Use it from Python
Run migrations when your app starts:
from sqlalchemy import create_engine
from dblift.api import DBLiftClient
engine = create_engine("postgresql+psycopg://user:pass@localhost/app")
with DBLiftClient.from_sqlalchemy(engine, migrations_dir="migrations") as client:
client.migrate()
AsyncDBLiftClient (from dblift.api.async_client import AsyncDBLiftClient) does the same without blocking an event loop. API → · Async client →
Give your tests a migrated database:
pip install pytest-dblift
def test_schema_is_current(dblift_migrated_db, dblift_client):
assert dblift_client.info().pending_count == 0
Integrations: Django management commands and system check · FastAPI · Flask · SQLAlchemy · OpenTelemetry spans · CI/CD recipes for GitHub Actions, GitLab CI and pre-commit · an MCP server for AI assistants.
How it compares
| DBLift | Flyway Community | Alembic | Your own script | |
|---|---|---|---|---|
Migrations are plain .sql files |
✅ | ✅ | Python revision files | ✅ |
| Runs without a JVM | ✅ | ❌ | ✅ | ✅ |
| Undo | ✅ | paid editions | ✅ downgrade() in Python |
if you wrote it |
| Preview the SQL before applying | ✅ | paid editions | ✅ offline --sql mode |
if you wrote it |
| Detects edited or duplicated migrations | ✅ | ✅ | ❌ | rarely |
| Importable as a Python library | ✅ | ❌ | ✅ | — |
| pytest fixtures | ✅ | ❌ | third-party plugin | — |
| Adopts an existing Flyway history | ✅ | — | ❌ | ❌ |
Alembic is the right choice when your schema is driven by SQLAlchemy models and you want autogenerated revisions. DBLift is for teams who write the SQL themselves.
Databases
20 engines. SQLite works with a bare pip install dblift; every other engine has its own install extra, e.g. pip install "dblift[postgresql]".
PostgreSQL · MySQL · MariaDB · SQL Server · Oracle · DB2 · SQLite · DuckDB · CockroachDB · Redshift · Snowflake · Neon · Supabase · Aurora PostgreSQL · AlloyDB · YugabyteDB · TimescaleDB · Citus · Azure Cosmos DB · MongoDB
What each engine supports is in the capability matrix; connection details are under Engines.
What Pro adds
The OSS tier covers the full migration lifecycle: apply, preview, validate state, roll back, and import from Flyway. When review risk grows, the Pro tier adds:
| Feature | Command | What it does |
|---|---|---|
| Schema drift detection | dblift diff |
Compares live database state with what your migrations define. Surfaces objects that have drifted. |
| Schema export | dblift export-schema |
Exports the current schema to SQL migration files. Useful for brownfield onboarding. |
See pricing and Pro features →
Documentation
Everything lives at docs.dblift.com.
Project
- Released on PyPI with trusted publishing — see the changelog and releases.
- Questions, ideas, "would this work for us?" Ask in Discussions.
- Found a bug? Open an issue. Reports with a failing migration file attached get fixed fastest.
- Want to contribute? See CONTRIBUTING.md.
- Security: see SECURITY.md.
- License: Apache 2.0.
If DBLift saved you a JVM or a migrate.sh, a ⭐ helps other teams find it.
Metadata
Release files for dblift 4.11.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dblift-4.11.0.tar.gz | 993.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dblift-4.11.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.2 MB
Release files / dblift-4.11.0.tar.gz
| Download URL | dblift-4.11.0.tar.gz |
|---|---|
| Size | 993.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0ba21c883daafd08de045eb993433f505fa6eb40794672e3c0aad4d13762acd4
|
|
BLAKE2b-256 checksum How to use checksums |
8797825db4dcb2939b9e7e4688c35deb181024ff072d82d2d5bf909009aef63c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logRelease files / dblift-4.11.0-py3-none-any.whl
| Download URL | dblift-4.11.0-py3-none-any.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5d1c2b1593212b94ff505708bcbc8d503d68de854b5f372cacdbc09b251eb531
|
|
BLAKE2b-256 checksum How to use checksums |
f5366a951d4e91e37a88484bc754a5b13ffb4c51c24ea723b3d7210d283479a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency log