Skip to main content

Migrations overview

Your Go structs are the source of truth. diff compares them with a stored snapshot and writes the difference out as plain SQL. You read the file, edit it if you need to, and up applies it.

  1. Change a structAdd a field, a tag, an index
  2. diffCompares models with a snapshot. No database needed
  3. Read the .sqlPlain SQL, yours to edit. Warnings sit above risky lines
  4. upApplies it, under a lock, once

Generating doesn't need a database, and every migration is ordinary SQL, so any tool can read the files and you can stop using ant's runner whenever you like. There are no down migrations: to undo a change, you write a new one.

Migrations run on PostgreSQL. The other databases return schema.ErrUnsupported for now.

Set up​

Go can't load your structs from another module, so the CLI is a tiny program that lives in yours.

cmd/migrate/main.go
package main

import (
_ "github.com/jackc/pgx/v5/stdlib"

"github.com/skudra-go/ant/dialect/postgres"
"github.com/skudra-go/ant/migrate"

"example.com/app/models"
)

func main() {
migrate.Main[models.AppDB](postgres.Dialect)
}

The first migration​

export DATABASE_URL='postgres://user:password@localhost:5432/app?sslmode=disable'

go run ./cmd/migrate diff create_tables
go run ./cmd/migrate up

That gives you this, and you commit all of it. The snapshot is what the next diff compares against.

migrations/
├── versions/
│ ├── 0001_create_tables.up.sql runs once
│ └── schema.snapshot.json what the models looked like
└── code/ reruns when a file changes

Daily work​

Change a struct, then:

go run ./cmd/migrate diff add_bio # writes 0002_add_bio.up.sql
# read the file
go run ./cmd/migrate up

diff --dry-run prints the SQL without writing anything. status lists every migration and where it stands, and drift compares the live database with what migrations describe.

In CI​

check fails if someone changed a struct without generating a migration. It doesn't need a database, so it's cheap to run in CI.

go run ./cmd/migrate check

Next​