> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hackutd.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrations for forks

> Why migration numbering is load-bearing and how forks avoid breaking it

Harp's database migrations are managed with golang-migrate. This page explains the numbering contract and the procedure a fork follows when its migration number collides with upstream's.

## 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.sh` runs 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 the `schema_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

1. 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`).
2. Renumber yours, never upstream's. Move your migration above upstream's new maximum.
3. If yours already ran in production, renumbering changes its identity. Hand-fix the `schema_migrations` table before running `migrate up` again, and do this before your next event, not during it.
4. 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.

## Day-to-day commands

```bash theme={null}
task migrate-create   # scaffold a new numbered migration pair
task migrate-check    # run the same contiguity check CI runs
task migrate-up       # apply pending migrations
task migrate-down     # roll back
```
