Database migrations
Drizzle ORM manages schema in apps/api/src/db/schema/ and generates migrations via drizzle-kit.
Workflow
Local
# After editing schema
pnpm --filter @gringo-pay/api db:generate
# Apply to your local dev DB (uses NEON_DB_URL from .dev.vars)
pnpm --filter @gringo-pay/api db:migrate
Production
Migrations run as the first step of the API deploy job (.github/workflows/cd.yml):
- name: Run database migrations
run: pnpm --filter @gringo-pay/api db:migrate
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
The API deploy only proceeds if migrations succeed. Wrangler deploy runs after.
Neon branches for tests
CI uses TEST_NEON_DB_URL — a separate Neon branch DB the tests can reset between runs. Do not point tests at the production branch.
Rules
- Never edit an already-applied migration. Always generate a new one.
- Never drop columns or tables without a deprecation window — old Workers versions may still be running during a deploy roll-out.
- Keep migrations reversible in principle. Drizzle doesn't generate
downmigrations, but write forwards migrations that could be reversed by a follow-up if needed. - Backfills belong in migrations, not in application code. If a new column needs data, backfill it in the same migration that adds it.
Rollback
If a migration is bad but already applied:
- Do not try to reverse the migration in place — write a follow-up migration that undoes / fixes it.
- If the API deploy is failing because of the new migration,
wrangler rollbackthe API and ship the fix migration.