Alembic
Database migration tool for SQLAlchemy. Manages schema versioning via migration scripts. Current version: 1.18.4 (Mar 2026). Tightly coupled to SQLAlchemy — version mismatch causes silent failures. SQLAlchemy 1.3 dropped in Alembic 1.15. Python 3.8 dropped in Alembic 1.15. The #1 footgun: autogenerate generates empty migrations when target_metadata is not correctly set in env.py.
Warnings
- breaking target_metadata = None in env.py causes autogenerate to produce completely empty migration files. This is the default after 'alembic init'. Must be changed to Base.metadata.
- breaking 'Target database is not up to date' error when running --autogenerate. DB must be at head before generating new migrations.
- breaking SQLAlchemy 1.3 support dropped in Alembic 1.15. Python 3.8 support dropped in Alembic 1.15.
- gotcha Autogenerate cannot detect everything. It misses: stored procedures, views, partial indexes (pre-1.12), CHECK constraints, column defaults (in some cases). Always manually review generated migrations.
- gotcha Multiple heads error: 'Multiple head revisions are present' when two migrations both point to the same parent. Happens when multiple developers generate migrations from the same base.
- gotcha Autogenerate generates 'create table' for all tables instead of 'add column' when models are not imported before autogenerate runs. Models must be imported in env.py so SQLAlchemy metadata is populated.
- gotcha alembic.ini sqlalchemy.url hardcodes the database URL. For production, override it in env.py using environment variables.
Install
-
pip install alembic
Imports
- env.py target_metadata
# In alembic/env.py — MUST import your models for autogenerate to work from myapp.models import Base # import all models so metadata is populated target_metadata = Base.metadata # If models are in multiple files, import them all: from myapp.models.user import User from myapp.models.post import Post # then: target_metadata = Base.metadata
- alembic init + upgrade
# CLI commands — run from project root alembic init alembic # create alembic directory alembic revision --autogenerate -m 'initial' # generate migration alembic upgrade head # apply all pending migrations alembic downgrade -1 # roll back one migration alembic history # show migration history alembic current # show current DB version
Quickstart
# 1. Install and init
# pip install alembic sqlalchemy
# alembic init alembic
# 2. Edit alembic/env.py — add your models:
# from myapp.models import Base
# target_metadata = Base.metadata
# 3. Edit alembic.ini — set database URL:
# sqlalchemy.url = postgresql://user:pass@localhost/mydb
# 4. Generate first migration
# alembic revision --autogenerate -m 'initial schema'
# 5. Apply migration
# alembic upgrade head
# Migration file (alembic/versions/xxx_initial_schema.py):
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'users',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('username', sa.String(50), nullable=False),
sa.Column('email', sa.String(120), nullable=False),
)
def downgrade():
op.drop_table('users')