Migration Numbering¶
Source: hooks/ways/data/migrations/numbering/numbering.md
Frontmatter
| Field | Value |
|---|---|
description |
how migration files are numbered, ordered, and tracked — the applied-migrations ledger, gap-tolerant sequencing, and avoiding number collisions |
vocabulary |
numbering sequence order version ledger applied filename prefix zero-pad monotonic gap collision timestamp schema_migrations sequential |
pattern |
schema_migrations|migration.?(number|order|sequenc|version|ledger)|zero.?pad|\b0\d\d_|applied_at |
refire |
0.15 |
scope |
agent, subagent |
A migration's number is its identity. The rules that keep a history sane are about never disturbing a number once it exists, because downstream databases have already recorded it.
The rules¶
- Monotonic, append-only. New migrations take the next number. Never renumber or reuse one — a database that already applied
042will never see your new042. - Zero-pad the filename (
001_,002_) so lexical order matches numeric order, but compare as integers in code (strip leading zeros) —10#$nin bash,int(...)elsewhere. - Gaps are fine. If
002and010were never used or later dropped, readers skip them. Don't backfill or renumber to close a gap. - One ledger table (commonly
schema_migrations) records applied versions. The runner applies only the files whose number isn't in the ledger yet.
Collisions¶
Two branches both adding 081 collide. Resolve it before merge: renumber the not-yet-landed one to the next free number. For large teams where this happens constantly, timestamp-prefixed names (20260702_…) trade readability for collision-freedom — pick sequential for small teams, timestamps for busy ones.
See Also¶
- data/migrations/idempotent(data) — the ledger insert must be idempotent too
- data/migrations/checkpoint(data) — consolidating a long, gappy history