Skip to content

Migrations

SAE Books uses Alembic for schema migrations. Migration files live in alembic/versions/ and follow the convention NNNN_short_slug.py where NNNN is a 4-digit zero-padded sequence (e.g. 0170_ephemeral_demo_tenants.py).

Tip

Migration IDs go up monotonically across all branches. Don't reuse a number — if you cherry-pick a migration into a different chain, renumber to the next free slot. Alembic will reject a duplicate revision ID at runtime, but the friendly fix is to avoid the collision in the first place.

Adding a migration

The Makefile revision target wraps alembic revision:

make revision m="add foo to bar"
# → alembic/versions/NNNN_add_foo_to_bar.py

For an autogenerated diff from your model changes, run the command directly:

docker compose exec app alembic revision --autogenerate -m "add foo to bar"

Review the generated diff carefully — Alembic autogen handles columns and indexes well but has known blind spots (server defaults, check constraints, enum types). Hand-edit where needed.

Applying

# Via Makefile (recommended during development)
make migrate

# Or directly
docker compose exec app alembic upgrade head

Rollback

docker compose exec app alembic downgrade -1

downgrade -1 walks back one revision. Be cautious in prod — downgrades that drop columns or tables are destructive.

Production deploys

entrypoint.sh runs alembic upgrade head before starting uvicorn on every container start. If a migration fails, the container exits non-zero and the orchestrator restarts it. To force a manual run, exec into a healthy container and run alembic upgrade head interactively, then restart the container.

Warning

Migration 0128_app_role reads SAEBOOKS_APP_DB_PASSWORD from the environment. This variable must be set in the compose .env before running migrations on a fresh database; the migration refuses to apply if the variable is absent or empty.