ADR-002: Database Migration Tool
Date: 2025-04-30
Status: Accepted
Context
Section titled “Context”As the application evolves, the database schema will need to change. We need a reliable and consistent way to manage and apply these schema changes across different environments (development, testing, production).
Key requirements for a migration tool include:
- Versioning of schema changes.
- Ability to apply migrations sequentially (up).
- Ability to revert migrations (down).
- Integration with our development and CI/CD workflows.
- Compatibility with PostgreSQL (used by Supabase).
Decision
Section titled “Decision”We will use golang-migrate (https://github.com/golang-migrate/migrate) as our database migration tool.
Migrations will be written as pairs of raw SQL files (.up.sql and .down.sql) stored in the migrations/ directory.
The Taskfile.yml will include tasks to create new migration files and apply/revert migrations using the golang-migrate CLI against the configured DATABASE_URL.
Consequences
Section titled “Consequences”Positive:
- SQL-First: Allows direct use of PostgreSQL features and syntax in migrations.
- Simplicity:
golang-migrateis a focused tool with a clear CLI interface. - Widely Adopted: It’s a standard and well-understood tool in the Go ecosystem.
- Language Agnostic: Migrations are plain SQL, not tied to Go code constructs.
- Explicit Control: Schema changes are explicit and version-controlled.
Negative:
- External Tool: Requires installing and managing the
golang-migrateCLI tool. - Manual SQL: Requires writing raw SQL for both
upanddownmigrations (no automaticdowngeneration). - No Go Integration: Migrations are managed outside the Go application binary itself (though can be embedded if desired, we opt for CLI usage initially).
Alternatives Considered
Section titled “Alternatives Considered”- ORM Auto-Migration (e.g., GORM): Rejected because we are not using a full ORM, and auto-migration can be opaque and risky in production environments.
- Atlas: A powerful, modern schema management tool. Considered more complex than needed for our initial setup, but could be revisited later.
- sqlc Migrations (Experimental):
sqlchas some experimental migration features, butgolang-migrateis more mature and purpose-built for this task. - dbmate: Similar to
golang-migrate, also a viable option, butgolang-migrateis slightly more prevalent in the Go ecosystem.
References
Section titled “References”golang-migrateRepository: https://github.com/golang-migrate/migrate
Enforcement
Section titled “Enforcement”- Testable consequences:
- TC-1: Every
migrations/*.up.sqlhas a matching*.down.sql, and vice versa; migrations are raw SQL files.
- TC-1: Every
- Checks:
- TC-1 →
adr002-migration-pairsinscripts/adrcheck(status: block, promoted 2026-09-30)
- TC-1 →
- Not machine-checkable: That a down migration actually reverts its up migration — revert safety is review territory.
- Graduation log:
- 2026-09-30 — promoted warn → block (ADR-033 §4): clean since 2026-07-12 (80 days, zero false positives; the rule asks for 7).
checks/enforcement.config.jsoncarriesgraduated: 2026-09-30. Demotion back to warn is allowed with the same trail.
- 2026-09-30 — promoted warn → block (ADR-033 §4): clean since 2026-07-12 (80 days, zero false positives; the rule asks for 7).