Database Migration Workflow
Database Migration Workflow
Alembic manages PostgreSQL schema migrations. Migration files live in backend/app/alembic/versions/.
Creating a Migration
After modifying SQLModel models in backend/app/models/:
Always review the generated file before committing. Autogenerate does not handle every case — check for:
- Correct table/column creation and deletion
- ENUM type drops in
downgrade()(see below) - Index creation (GIN indexes from
__table_args__may need manual addition) - Correct foreign key constraint ordering in downgrade (children before parents)
Applying Migrations
Downgrading
Verifying No Drift
After applying migrations, check that models and DB schema are in sync:
If the generated migration contains only pass in both upgrade() and downgrade(), there is no drift. Delete the empty file.
Handling ENUM Types
Alembic autogenerate does not emit DROP TYPE statements in downgrade() for PostgreSQL ENUM types. After generating a migration that creates enums, manually add drops at the end of downgrade():
Without this, alembic downgrade base leaves orphan enum types in the database.
Resolving Migration Conflicts
If two branches both add migrations, the second branch to merge will have a down_revision pointing to a revision that is no longer the head.
To resolve:
- Delete the conflicting migration on your branch
- Rebase onto the target branch
- Regenerate the migration:
make db-migrate MSG="your description"
Pre-commit Checklist
Before committing a new migration:
-
alembic upgrade headsucceeds on a clean database -
alembic downgrade baseleaves zero tables and enum types -
alembic revision --autogenerateshows no drift (empty migration) - Downgrade drops all ENUM types created in upgrade
-
ruff check .andruff format --check .pass