| name | database-branching |
|---|---|
| description | Use when building any feature that involves database changes (new table, new column, alter column, etc.) — fork the database like a git branch. Only applies to projects using Ghost DB. |
Treat database forks like git branches. Never make schema changes directly on the production database. Fork it, develop against the fork, merge migrations back when ready, then delete the fork.
This skill only applies to projects using Ghost DB (TimescaleDB Cloud). If the project uses Supabase, local Postgres, or another database service, this skill does not apply.
Any time a feature involves database changes:
- Adding a new table
- Adding or removing columns
- Altering column types or constraints
- Adding indexes
- Changing enums
- Any DDL operation whatsoever
Even for "small" changes. A single ALTER TABLE ADD COLUMN still gets a fork. The cost of forking is low (2 minutes). The cost of breaking production is high.
- Feature has zero database changes (pure application logic, API changes, frontend)
- Project does not use Ghost DB
- Quick read-only queries against production (use
ghost_sqldirectly)
Check for these signals:
mcp__ghost__tools are available.envorCLAUDE.mdreferences a Ghost database ID (10-char alphanumeric, e.g.,r7mf0mo24b)CLAUDE.mdmentions Ghost, TimescaleDB, orghost_list
If none of these are present, this skill does not apply.
Like git checkout -b feature/my-feature, but for the database.
mcp__ghost__ghost_list # Find your source DB ID
mcp__ghost__ghost_fork
id: "{source_db_id}"
name: "{project}-{feature}" # e.g., "sync-hq-auth", "sync-hq-webhooks"
Forking takes 90-120 seconds. Poll with ghost_list every 15-20 seconds until the fork shows as running. Do not give up early.
mcp__ghost__ghost_connect
id: "{fork_id}"
Update .env to point to the fork:
# Comment out production URL
# DATABASE_URL=postgresql://...production...
# Use fork for development
DATABASE_URL=postgresql://...fork...Before making any schema changes, check if the project uses a migration tool:
| Tool | How to Detect | Migration Command |
|---|---|---|
| Alembic (Python) | alembic.ini or alembic/ directory exists |
alembic revision --autogenerate -m "description" |
| Prisma (Node.js) | prisma/schema.prisma exists |
npx prisma migrate dev --name description |
| Drizzle (Node.js) | drizzle.config.ts exists |
npx drizzle-kit generate |
| Django | manage.py exists |
python manage.py makemigrations |
| Raw SQL | No migration tool found | Track changes manually in SQL files |
All schema changes must go through the migration tool. Never run raw DDL (CREATE TABLE, ALTER TABLE) directly against the database unless the project has no migration tool. Migrations are how changes get tracked, reviewed, and applied consistently.
This is where you spend most of your time:
- Modify models/schema in code (e.g.,
models.py,schema.prisma) - Generate a migration using the project's migration tool
- Apply the migration to the fork:
alembic upgrade head # or equivalent - Write tests and implementation (see test-driven-development skill)
- Verify with queries:
mcp__ghost__ghost_schema id: "{fork_id}" # Check schema looks right mcp__ghost__ghost_sql id: "{fork_id}" query: "SELECT ..." # Spot-check data
Iterate freely. If a migration is wrong, you can rollback (alembic downgrade -1), fix it, and re-apply. The fork is disposable.
- Autogenerated migrations may reference
sqlmodel.sql.sqltypes.AutoStringwithout importing it — always addimport sqlmodelto migration files or replace withsa.VARCHAR() - Enum changes (
ALTER TYPE ... ADD VALUE) require manual SQL in the migration — Alembic can't autogenerate these - Review every autogenerated migration before applying — they are not always correct
When the feature is complete and tested:
-
Merge the git branch (PR, merge to main, etc.)
-
Switch
.envback to production:DATABASE_URL=postgresql://...production...
-
Run migrations on production:
alembic upgrade head # or equivalent -
Verify production — spot-check the schema:
mcp__ghost__ghost_schema id: "{production_db_id}" -
Delete the fork:
mcp__ghost__ghost_delete id: "{fork_id}"
Do not skip the delete. Forks consume resources. Clean up after yourself.
If the feature is cancelled or the approach didn't work:
- Delete the fork — no migration needed:
mcp__ghost__ghost_delete id: "{fork_id}" - Discard the migration files in git (revert/delete)
- Restore
.envto production
When the app is deployed (e.g., Render, Railway, Fly.io):
- The deployed app uses a
DATABASE_URLenvironment variable pointing to production - After merging a feature with migrations, you may need to manually run migrations on the deployed database
- Some platforms support release commands (e.g., Render's "Build Command" or "Pre-Deploy Command") where you can add
alembic upgrade head - If the platform doesn't support release commands, you'll need to run migrations manually after deploy (e.g., via the platform's shell or by connecting to the DB directly)
- This is an open question for each project — document the deploy migration strategy in CLAUDE.md once established
This skill complements:
- plan-driven-development — The plan tracks what to build. This skill handles how to safely make database changes during that build. If a plan milestone involves DB changes, fork before starting that milestone.
- test-driven-development — TDD handles how to test. Tests run against the development fork (or a separate test fork if you need additional isolation). This skill ensures the fork exists before tests run.
Ownership boundaries:
- Database fork lifecycle (create, develop, merge, delete) → this skill
- What to build and progress tracking → plan-driven-development
- How to write and run tests → test-driven-development
| Action | Tool | Key Parameter |
|---|---|---|
| List DBs | mcp__ghost__ghost_list |
— |
| Fork | mcp__ghost__ghost_fork |
id (source DB) |
| Connect | mcp__ghost__ghost_connect |
id (fork) |
| Query | mcp__ghost__ghost_sql |
id, query |
| Schema | mcp__ghost__ghost_schema |
id |
| Delete | mcp__ghost__ghost_delete |
id (fork) |