SerpentStack db-migrate
Manage database schema changes with Alembic. Use when: creating migrations, adding tables or columns, checking migration status, rolling back, or seeding the database.
install
source · Clone the upstream repo
git clone https://github.com/Benja-Pauls/SerpentStack
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Benja-Pauls/SerpentStack "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.skills/db-migrate" ~/.claude/skills/benja-pauls-serpentstack-db-migrate && rm -rf "$T"
manifest:
.skills/db-migrate/SKILL.mdsource content
Database Migrations
Manage database schema changes with Alembic in SerpentStack.
Prerequisites
- Postgres running:
docker compose up -d postgres - Backend dependencies installed:
cd backend && uv sync
Creating a New Migration
After modifying or adding a SQLAlchemy model:
cd backend && uv run alembic revision --autogenerate -m "describe the change"
The migration description should be concise and specific, e.g., "add projects table", "add email column to users", "create index on tasks.status".
Review the generated file in
backend/migrations/versions/. Verify:
- The
function contains the expectedupgrade()
,op.create_table
, orop.add_column
calls.op.create_index - The
function is the inverse of upgrade.downgrade() - No unintended changes are included (Alembic sometimes detects phantom diffs).
Running Migrations
Apply all pending migrations:
cd backend && uv run alembic upgrade head
Apply only the next migration:
cd backend && uv run alembic upgrade +1
Checking Migration Status
See the current revision:
cd backend && uv run alembic current
See full migration history:
cd backend && uv run alembic history --verbose
Downgrading
Roll back the last migration:
cd backend && uv run alembic downgrade -1
Roll back to a specific revision:
cd backend && uv run alembic downgrade <revision_id>
Adding a New Table
Full workflow:
- Create the model file at
— inherit frombackend/app/models/{name}.py
(providesBase
,id
,created_at
).updated_at - Import the model in
so Alembic detects it.backend/app/models/__init__.py - Generate the migration:
.cd backend && uv run alembic revision --autogenerate -m "add {name}s table" - Review the generated migration file.
- Apply:
.cd backend && uv run alembic upgrade head - Verify: connect to the database and confirm the table exists.
Adding a Column to an Existing Table
- Edit the model in
-- add the new column.backend/app/models/{name}.py - Generate:
.cd backend && uv run alembic revision --autogenerate -m "add {column} to {name}s" - Review: ensure only the expected
is present.op.add_column - Apply:
.cd backend && uv run alembic upgrade head
Troubleshooting
| Problem | Solution |
|---|---|
| Run first |
| Check for correct |
| Phantom diffs in autogenerate | Compare model against DB schema manually; add to Alembic's list if needed |
| The migration was partially applied. Check table and fix manually |
| Migration conflicts (multiple heads) | Run |
on model import | Ensure model is imported in |
| Docker not running | Testcontainers and local Postgres both require Docker Desktop to be running |
Seed Data
Populate the database with sample development data:
make seed
This runs the async seed CLI command at
backend/app/cli/seed.py. The seed script is idempotent — running it multiple times will not create duplicates (it checks for existing rows first).