$npx -y skills add TerminalSkills/skills --skill alembicManage database migrations with Alembic. Use when a user asks to version database schemas, create migration scripts, handle schema changes in production, or manage SQLAlchemy model migrations.
| 1 | # Alembic |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Alembic is the migration tool for SQLAlchemy. It tracks database schema changes as versioned Python scripts — like Git for your database. Supports autogeneration from model changes, branching, and data migrations. |
| 6 | |
| 7 | ## Instructions |
| 8 | |
| 9 | ### Step 1: Setup |
| 10 | |
| 11 | ```bash |
| 12 | pip install alembic |
| 13 | alembic init alembic |
| 14 | ``` |
| 15 | |
| 16 | ```python |
| 17 | # alembic/env.py — Configure with async SQLAlchemy |
| 18 | from alembic import context |
| 19 | from sqlalchemy.ext.asyncio import create_async_engine |
| 20 | from models import Base |
| 21 | import asyncio |
| 22 | |
| 23 | config = context.config |
| 24 | target_metadata = Base.metadata |
| 25 | |
| 26 | def run_migrations_online(): |
| 27 | connectable = create_async_engine(config.get_main_option("sqlalchemy.url")) |
| 28 | |
| 29 | async def do_run(): |
| 30 | async with connectable.connect() as connection: |
| 31 | await connection.run_sync(do_migrations) |
| 32 | |
| 33 | def do_migrations(connection): |
| 34 | context.configure(connection=connection, target_metadata=target_metadata) |
| 35 | with context.begin_transaction(): |
| 36 | context.run_migrations() |
| 37 | |
| 38 | asyncio.run(do_run()) |
| 39 | |
| 40 | run_migrations_online() |
| 41 | ``` |
| 42 | |
| 43 | ### Step 2: Create Migrations |
| 44 | |
| 45 | ```bash |
| 46 | # Auto-generate from model changes |
| 47 | alembic revision --autogenerate -m "add projects table" |
| 48 | |
| 49 | # Create empty migration (for data migrations) |
| 50 | alembic revision -m "backfill user roles" |
| 51 | ``` |
| 52 | |
| 53 | ```python |
| 54 | # alembic/versions/001_add_projects.py — Generated migration |
| 55 | def upgrade(): |
| 56 | op.create_table('projects', |
| 57 | sa.Column('id', sa.String(36), primary_key=True), |
| 58 | sa.Column('name', sa.String(100), nullable=False), |
| 59 | sa.Column('owner_id', sa.String(36), sa.ForeignKey('users.id')), |
| 60 | sa.Column('created_at', sa.DateTime, server_default=sa.func.now()), |
| 61 | ) |
| 62 | op.create_index('ix_projects_owner_id', 'projects', ['owner_id']) |
| 63 | |
| 64 | def downgrade(): |
| 65 | op.drop_index('ix_projects_owner_id') |
| 66 | op.drop_table('projects') |
| 67 | ``` |
| 68 | |
| 69 | ### Step 3: Data Migrations |
| 70 | |
| 71 | ```python |
| 72 | # alembic/versions/002_backfill_roles.py — Data migration |
| 73 | from alembic import op |
| 74 | import sqlalchemy as sa |
| 75 | |
| 76 | def upgrade(): |
| 77 | # Add column |
| 78 | op.add_column('users', sa.Column('role', sa.String(20), server_default='member')) |
| 79 | |
| 80 | # Backfill existing rows |
| 81 | conn = op.get_bind() |
| 82 | conn.execute(sa.text("UPDATE users SET role = 'admin' WHERE email LIKE '%@mycompany.com'")) |
| 83 | |
| 84 | def downgrade(): |
| 85 | op.drop_column('users', 'role') |
| 86 | ``` |
| 87 | |
| 88 | ### Step 4: Commands |
| 89 | |
| 90 | ```bash |
| 91 | alembic upgrade head # apply all pending migrations |
| 92 | alembic downgrade -1 # rollback one migration |
| 93 | alembic history # show migration history |
| 94 | alembic current # show current revision |
| 95 | alembic upgrade +1 # apply next migration only |
| 96 | ``` |
| 97 | |
| 98 | ## Guidelines |
| 99 | |
| 100 | - Always review autogenerated migrations — they may miss renames (detected as drop+create). |
| 101 | - Run migrations in CI before deploying — catch schema issues early. |
| 102 | - Data migrations should be idempotent — safe to run multiple times. |
| 103 | - Use `op.batch_alter_table()` for SQLite (which doesn't support ALTER TABLE well). |
| 104 | - Never edit applied migrations — create new ones instead. |