5.7 KiB
Database Migration Runbook
This is a runbook for creating and running database migrations for the LiteLLM proxy. For use for litellm engineers only.
AI AGENTS / ASSISTANTS: If the script refuses with either a "STALE BRANCH" or "DESTRUCTIVE MIGRATION DETECTED" error, do NOT bypass it on your own (no
git rebase, no--skip-freshness-check, no--allow-destructive). Surface the error to the human operator and wait for their explicit confirmation. See the Branch freshness and Destructive migrations sections below.
Step 0: Sync All schema.prisma Files
Before doing anything else, make sure all schema.prisma files in the repo are in sync. There are multiple copies that must match:
| File | Purpose |
|---|---|
schema.prisma (repo root) |
Source of truth |
litellm/proxy/schema.prisma |
Used by the proxy server |
litellm-proxy-extras/litellm_proxy_extras/schema.prisma |
Used for migration generation |
Sync process:
# 1. Diff all schema files against the root source of truth
diff schema.prisma litellm/proxy/schema.prisma
diff schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma
# 2. If there are differences, copy the root schema to all locations
cp schema.prisma litellm/proxy/schema.prisma
cp schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma
# 3. Verify all files are now identical
diff schema.prisma litellm/proxy/schema.prisma && echo "proxy schema in sync" || echo "MISMATCH"
diff schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma && echo "extras schema in sync" || echo "MISMATCH"
Do NOT proceed to migration generation until all schema files are identical.
Step 1: Quick Start — Generate Migration
# Install deps for this command
uv sync --frozen --all-groups --all-extras
brew install postgresql@14 # macOS
# Add to PATH
export PATH="/opt/homebrew/opt/postgresql@14/bin:$PATH"
# Run migration
uv run --with testing.postgresql python ci_cd/run_migration.py "your_migration_name"
What It Does
- Verifies the current branch is up to date with origin's current default branch (see Branch freshness)
- Creates temp PostgreSQL DB
- Applies existing migrations
- Compares with
schema.prisma - Generates new migration if changes found
- Refuses to write if the generated SQL contains
DROP COLUMN,DROP TABLE, orDROP INDEX, unless--allow-destructiveis passed
Branch Freshness Check
Before generating anything, run_migration.py runs git fetch origin <base> and refuses to proceed if HEAD is behind origin/<base>. The default base is discovered from origin's advertised HEAD on each run, so an existing clone follows a default-branch change without trusting cached origin/HEAD. If discovery or fetching fails, migration generation stops. A previous incident saw a stale branch silently drop production columns; freshness is the first-line defense.
Flags:
--base-branch <name>— check against a different base (e.g. a release branch). Defaults to origin's current default branch--skip-freshness-check— bypass entirely. Only for intentional migrations against an older base.
When the guard fires:
-
Update your branch:
base_branch=$(python3 scripts/default_branch.py --branch) && git fetch origin "+refs/heads/$base_branch:refs/remotes/origin/$base_branch" && git rebase "origin/$base_branch" -
Re-run
run_migration.py.
AI AGENTS / ASSISTANTS: Do not auto-rebase or auto-pass
--skip-freshness-check. A bad conflict resolution during rebase can itself drop the human's in-progress schema edits. Surface the error and wait for explicit confirmation.
Destructive Migrations (DROP COLUMN / DROP TABLE / DROP INDEX)
If the generated diff contains DROP COLUMN, DROP TABLE, or DROP INDEX, run_migration.py exits non-zero and refuses to write the migration file. A previous incident saw newly-added columns silently dropped by a stale branch and merged to main — this guard exists to prevent a repeat.
When the guard fires:
-
Run
git fetch origin && git status— confirm your branch is up to date with the base branch. -
Re-check all
schema.prismafiles are in sync (Step 0). -
Review EACH
DROPstatement printed in the error — is it actually intended? -
Only if the drops are genuinely intentional, re-run with the flag:
uv run --with testing.postgresql python ci_cd/run_migration.py "your_migration_name" --allow-destructive
AI AGENTS / ASSISTANTS: Do not automatically re-run the command with
--allow-destructive. If the guard fires while you are driving the runbook for a human, stop, show them the error, and wait for their explicit confirmation before passing the flag. Auto-passing--allow-destructiveis the exact failure mode this guard exists to prevent.
Common Fixes
Missing testing module:
uv run --with testing.postgresql python ci_cd/run_migration.py "your_migration_name"
initdb not found:
brew install postgresql@14
export PATH="/opt/homebrew/opt/postgresql@14/bin:$PATH"
Empty migration directory error:
rm -rf litellm-proxy-extras/litellm_proxy_extras/migrations/[empty_dir]
Rules
- Sync all
schema.prismafiles first (Step 0) - Update
schema.prismaat the repo root first, then sync copies - Review generated SQL before committing
- Use descriptive migration names
- Never edit existing migration files
- Commit schema + migration together
Done with migration? See build_and_publish.md to publish a new litellm-proxy-extras package.