Live Alembic
Apply database migrations without migration files. Live Alembic uses Alembic's
autogeneration to diff your SQLAlchemy models against the live database and
applies DDL directly — no versions/ directory, no commit-to-run cycle.
Install
pip install live-alembic
Quickstart
1. Create migrate_env.py in your project root:
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
# SQLite
db_url = "sqlite:///myapp.db"
# PostgreSQL
# db_url = "postgresql+psycopg2://user:password@localhost/mydb"
# MySQL / MariaDB
# db_url = "mysql+pymysql://user:password@localhost/mydb"
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String(100))
email = Column(String(255))
target_metadata = Base.metadata
# Optional: List of tables to ignore (e.g. tables managed by other applications)
# ignore_tables = ["some_external_table"]
2. Check for pending changes:
livealembic check
Exits 0 if the schema is in sync, 1 if changes are pending.
3. Apply changes:
livealembic migrate
CLI Reference
livealembic check [--file PATH] [--format text|json] [--verbose]
livealembic migrate [--file PATH] [--format text|json] [--verbose]
livealembic --version
| Command | Description | Exit code |
|---|---|---|
check |
Show pending changes, do not apply | 1 if changes exist |
migrate |
Apply pending changes | 1 on error |
| Option | Default | Description |
|---|---|---|
--file PATH |
migrate_env.py |
Path to your configuration module |
--format json |
text |
Machine-readable JSON output |
--verbose |
off | Include raw operation details in output |
Example output
Create table "orders"
Add column 'phone' (VARCHAR(20)) to table 'users'
Drop column 'legacy_id' from table 'users'
Alter column 'status' on 'orders' to type INTEGER
CI / CD usage
# Fail the pipeline if the schema has drifted
livealembic check --file config/migrate_env.py
# Apply during deployment
livealembic migrate --file config/migrate_env.py
Package Entry Points
Other libraries can automatically include SQLAlchemy models into the application's migration metadata by registering an entry point under the live_alembic.models group. Live Alembic dynamically loads all registered entry points under this group and merges their tables into the application's target_metadata.
The entry point can point to:
- A SQLAlchemy
MetaDatainstance. - A SQLAlchemy Declarative Base (or registry) subclass with a
metadataattribute. - A SQLAlchemy
Tableobject. - A module—in which case Live Alembic will inspect its attributes to discover any
MetaData, Declarative Base, orTableinstances.
Example registration in a library's pyproject.toml:
[project.entry-points."live_alembic.models"]
my_library_models = "my_library.models:metadata"
Hooks
Define before_migrate, migrate_data and/or after_migrate in
migrate_env.py to run data migrations in the same transaction as the schema
change:
from live_alembic import Changes
from sqlalchemy import text
def before_migrate(changes: Changes, connection):
if changes.added_column("users", "full_name"):
connection.execute(
text("UPDATE users SET full_name = first_name || ' ' || last_name")
)
def after_migrate(changes: Changes, connection):
if changes.dropped_column("users", "legacy_token"):
connection.execute(text("DELETE FROM audit_log WHERE action = 'token_refresh'"))
A third hook, migrate_data, runs between the additive and the destructive
operations. Defining it splits the migration into two phases -- creates and
adds first, then the hook, then the drops and alters -- so the hook sees a
schema where both the old and the new structures exist. That is what an
installation which skipped a release needs, because it receives the new table
and the dropped column in the same migration:
def migrate_data(changes: Changes, connection):
if changes.created_table("user_emails") and changes.has_column("users", "email"):
connection.execute(text(
"INSERT INTO user_emails (user_id, address) "
"SELECT id, email FROM users WHERE email IS NOT NULL"
))
changes.has_column() reflects the live database at the moment the hook runs,
so it also keeps the hook from firing on a fresh install where the source
column never existed. Note that alter_column runs in the second phase, which
is what makes "add column, backfill, then set NOT NULL" work in a single pass.
All three hooks receive a Changes helper and the active connection. If a hook
raises, the transaction is rolled back (schema + data).
See documentation/usage/usage.org for the full hooks API, database-specific notes, and programmatic API docs.
Testing
Complete development tests require docker compose for database integration.
Local Tests
Run the standard test suite against SQLite (no Docker required):
make test
Database Integration Tests
Start database services and run tests against a specific backend:
make test-postgresql
make test-mysql
Or run against all supported databases sequentially:
make test-all
Test Matrix (Tox)
Run the full matrix of supported Python versions and databases:
make tox
Coverage
Generate a coverage report for the SQLite tests:
make coverage
Metadata
Release files for live-alembic 0.3.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| live_alembic-0.3.5.tar.gz | 28.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| live_alembic-0.3.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.4 kB
Release files / live_alembic-0.3.5.tar.gz
| Download URL | live_alembic-0.3.5.tar.gz |
|---|---|
| Size | 28.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c23219a53c20d9be7be0f613d6da559485c15507efd8dd6e231bdf794018c9d2
|
|
BLAKE2b-256 checksum How to use checksums |
b6df3e60d5f4b1959703d01fe493dcdbfa521ae84e97265515b65640ac995439
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / live_alembic-0.3.5-py3-none-any.whl
| Download URL | live_alembic-0.3.5-py3-none-any.whl |
|---|---|
| Size | 27.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cd3586229a7ddb96eb5ff241feda20dc72580c22ebddfdef9824107ba1d73627
|
|
BLAKE2b-256 checksum How to use checksums |
41ddf521bc4a3122d6189e625c9590110c5d311fff8acdf4f347b286e9f0b99c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|