3 min read
Vow: PostgreSQL Migration Runner for Go

Why I built Vow

I wanted to understand how database migration tools work underneath the abstraction.

I had already used migration tools like Goose and Flyway, so Vow was not built because I needed a migration tool. I wanted to understand what a migration runner actually has to handle, so I built one from scratch while working on Dhara.

Once the migration runner was working, I extracted it from Dhara into Vow so I could reuse it across my other Go projects. Dhara now uses Vow for its own database migrations.

Design

Vow is designed to be embedded directly into a Go application. It uses pgx and PostgreSQL, with no configuration files or CLI required.

Migrations are stored as paired .up.sql and .down.sql files and validated when the migrator is created. Vow uses PostgreSQL advisory locks so multiple application instances cannot run migrations concurrently.

Applied migrations are stored with SHA-256 checksums. Before running new migrations, Vow verifies that previously applied migrations have not been edited or deleted.

Vow also supports rolling back a chosen number of migrations through their corresponding .down.sql files. Rollbacks are intended for local development and test teardown rather than automatic production recovery.

Embeddable Migrations

Vow accepts any Go fs.FS, so migrations can be loaded from the filesystem or embedded directly into the application binary using //go:embed.

This keeps migrations close to the application code and makes Vow usable as a library without requiring a migrations directory to exist on the target machine.

Design Decisions

  • PostgreSQL advisory locks. Multiple service instances can start at the same time without running the same migration concurrently.
  • Checksums over filenames. Renaming a migration is not the only way to break migration history. Vow detects changes to the contents of already-applied migrations.
  • Paired up/down migrations. Every migration must have a corresponding rollback file, and both sides are validated up front.
  • No automatic rollback. If a migration fails during deployment, Vow stops and reports the failure instead of attempting an automatic undo. The decision to fix forward or roll back manually belongs to the operator.
  • fs.FS support. Migrations can come from the filesystem or be embedded into the application binary.
  • Minimal dependencies. Vow only relies on pgx for PostgreSQL access.

Tech Stack

Layer Technology
Language Go
Database PostgreSQL
PostgreSQL Driver pgx
Standard Library fs.FS ยท embed