Alembic patterns
Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/alembic-patterns
A curated pack of custom Claude Code skills for developers — installable as a Claude Code plugin marketplace.
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill alembic-patternsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
When to activate: Alembic, database migrations, schema changes, migration scripts, rollback, multi-head
SKILL.md
3.6 KB, as published. Nobody here has run it
Alembic Migration Patterns
Setup with SQLAlchemy async
# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import pool
from sqlalchemy.ext.asyncio import create_async_engine
from alembic import context
from app.models import Base
from app.core.config import settings
config = context.config
config.set_main_option("sqlalchemy.url", settings.database_url)
if config.config_file_name is not None:
fileConfig(config.config_file_name)
target_metadata = Base.metadata
def run_migrations_offline() -> None:
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url, target_metadata=target_metadata, literal_binds=True)
with context.begin_transaction():
context.run_migrations()
def do_run_migrations(connection) -> None:
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
async def run_async_migrations() -> None:
engine = create_async_engine(settings.database_url, poolclass=pool.NullPool)
async with engine.connect() as connection:
await connection.run_sync(do_run_migrations)
await engine.dispose()
def run_migrations_online() -> None:
import asyncio
asyncio.run(run_async_migrations())
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
Common Commands
# Generate migration (auto-detect model changes)
alembic revision --autogenerate -m "add_users_table"
# Apply migrations
alembic upgrade head # apply all pending
alembic upgrade +1 # apply next one
alembic upgrade <rev_id> # apply up to specific revision
# Rollback
alembic downgrade -1 # roll back one
alembic downgrade base # roll back all
# Inspect
alembic history --verbose # show history
alembic current # show current revision
alembic show <rev_id> # show migration details
Safe Migration Patterns
Adding nullable column (zero-downtime)
# Step 1: Add as nullable
def upgrade() -> None:
op.add_column("users", sa.Column("phone", sa.String(20), nullable=True))
# Step 2 (separate migration): backfill data
def upgrade() -> None:
op.execute("UPDATE users SET phone = '' WHERE phone IS NULL")
# Step 3 (separate migration): make not-null after backfill complete
def upgrade() -> None:
op.alter_column("users", "phone", nullable=False)
Renaming a column (zero-downtime)
# Step 1: Add new column, copy data
def upgrade() -> None:
op.add_column("users", sa.Column("full_name", sa.String(200)))
op.execute("UPDATE users SET full_name = name")
# Step 2 (after code deployed reading both): drop old column
def upgrade() -> None:
op.drop_column("users", "name")
Adding index without table lock
def upgrade() -> None:
op.create_index(
"ix_users_email",
"users",
["email"],
postgresql_concurrently=True, # CONCURRENTLY avoids table lock
)
Anti-Patterns
- Editing committed migrations (use a new migration instead)
- Data migrations in schema migrations (separate them)
op.drop_columnwithout confirming no code reads itnullable=Falsewithout a default or backfill- Using
--autogenerateand not reviewing the generated migration