The numbering contract
- Migrations are named
{6-digit version}_{description}.{up|down}.sql, one concern per migration. - Versions are strictly contiguous from
000001, with exactly one up and one down file per version. - CI enforces this:
scripts/check-migrations.shruns on every PR and fails on gaps or duplicate versions.
Why it has to be this way
golang-migrate stores a single integer version in theschema_migrations table and only ever applies migrations with a version strictly greater than it.
That makes numbering load-bearing, not cosmetic. It’s also why a fork can’t just pick a high number (say 000900) to stay out of upstream’s way: once your database is at version 900, every later upstream migration (000032, 000033, and so on) is silently skipped with no error.
The fork procedure
- Expect collisions. Upstream will eventually claim the number you used; the CI check will tell you (
version X is used by both A and B). - Renumber yours, never upstream’s. Move your migration above upstream’s new maximum.
- If yours already ran in production, renumbering changes its identity. Hand-fix the
schema_migrationstable before runningmigrate upagain, and do this before your next event, not during it. - Keep fork migrations rare: few, additive (new columns or tables), and at the tail. Prefer a runtime setting over a schema change wherever the choice exists.