🎓 What You Will Learn
- Alembic Setup: Initialize migrations for your project
- Creating Migrations: Auto-generate and write custom migrations
- Upgrading/Downgrading: Move between schema versions
- Data Migrations: Transform data while changing schema
- Production Deployment: Safe migration strategies
- Troubleshooting: Handle migration conflicts and rollbacks
1Why Database Migrations Matter
Without migrations, your database schema becomes untracked and unpredictable. Migrations provide version control for your database, allowing safe schema changes across development, staging, and production environments.
Best Practice: Every schema change should have a corresponding migration file, tracked in version control.
2Setting Up Alembic
Initialize Alembic in your FastAPI project.
pip install alembic sqlalchemy
alembic init migrationsfrom app.database import Base
from app.models import *
target_metadata = Base.metadata📋 Migration Timeline
3Creating Your First Migration
Auto-generate migrations from your SQLAlchemy models.
alembic revision --autogenerate -m "Create user table"4Understanding Migration Files
Migration files contain the schema changes and are tracked in version control.
from alembic import op
import sqlalchemy as sa
revision = "001"
down_revision = None
def upgrade():
op.create_table(
"user",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("email", sa.String(), nullable=False),
sa.Column("name", sa.String()),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("email")
)
def downgrade():
op.drop_table("user")5Applying and Rolling Back Migrations
Use Alembic commands to move between schema versions.
# Apply migrations
alembic upgrade head
# Upgrade to specific revision
alembic upgrade 001
# Rollback one migration
alembic downgrade -1
# Rollback to base
alembic downgrade base
# View migration history
alembic current
alembic history6Data Migrations
Transform data while changing schema.
from alembic import op
import sqlalchemy as sa
def upgrade():
# Add new column
op.add_column("user", sa.Column("phone", sa.String()))
# Migrate data
connection = op.get_bind()
connection.execute(sa.text("UPDATE user SET phone = '000-0000' WHERE phone IS NULL"))
def downgrade():
op.drop_column("user", "phone")7Adding Constraints and Indexes
Optimize performance with indexes and enforce data integrity with constraints.
from alembic import op
def upgrade():
op.create_index("idx_user_email", "user", ["email"])
op.create_check_constraint("ck_user_age", "user", "age >= 18")
def downgrade():
op.drop_index("idx_user_email")
op.drop_constraint("ck_user_age", "user")8Writing Custom Migrations
For complex logic, write migrations manually.
# Create empty migration
alembic revision -m "Custom logic"9Environment-Specific Migrations
Different migrations for dev, staging, and production.
# Development
alembic upgrade head
# Production (dry run first)
alembic upgrade head --sql > migrations.sql
# Review migrations.sql
alembic upgrade headSafety First: Always backup production before running migrations. Test migrations on a replica first.
10Handling Migration Conflicts
When multiple branches create migrations, resolve conflicts by renaming revisions.
# If two branches create 002_migration.py, rename one:
mv migrations/versions/002_add_field_a.py \
migrations/versions/003_add_field_a.py
# Update revision and down_revision fields in the file11Testing Migrations
Test migrations automatically.
import subprocess
def test_migrations_apply():
# Run migrations on test database
result = subprocess.run(
["alembic", "upgrade", "head"],
capture_output=True
)
assert result.returncode == 0
def test_migrations_rollback():
result = subprocess.run(
["alembic", "downgrade", "base"],
capture_output=True
)
assert result.returncode == 012Safe Production Migration Strategy
Best practices for production migrations.
- Backup first: Always backup production database before migrating
- Test on replica: Run migrations on a replica of production
- Downtime window: Schedule migrations during maintenance window
- Rollback plan: Know how to rollback quickly if needed
- Monitor: Watch application behavior after migration
Blue-Green Deployment: Run two identical production environments, migrate on blue, then switch traffic to blue.
13Common Migration Pitfalls
- Missing migrations: Schema changes without migrations create inconsistency
- Large batches: Don't migrate too many changes at once
- Non-idempotent migrations: Migrations should be safe to run twice
- No downgrade path: Always write downgrade logic
- Locking tables: Long-running migrations can lock tables
14Advanced Topics
- Zero-downtime migrations: Add columns, then migrate, then remove old column
- Parallel migrations: Run multiple migrations across shards
- Squashing migrations: Combine old migrations into one
- Conditional migrations: Run migrations based on environment
15Resources & What's Next
You now understand how to manage database schema changes safely. Use migrations for every change and track them in version control.
Next Topics: Security and authentication, deployment strategies, and monitoring.
Congratulations! Your database is now under version control. Deploy with confidence! 🚀