Help us shape the future of Go! Take the 2026 Go Developer Survey

migration

command module
v1.0.4-0...-bc3c7cf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 36 Imported by: 0

README

Migration Tool

MIT Licensed Go Version

Database migration tool for PostgreSQL and SQLite with transaction support, schema drift detection, and schema analytics. Pure Go, no cgo.

Beyond running SQL migration files, it can introspect a live PostgreSQL database, detect changes people made directly on it, and turn that drift into a reviewable up/down migration pair. It can also answer "what changed between version X and Y" from versioned schema snapshots.

Features

  • Transactions: each batch of migrations commits or rolls back as one
  • Multi-database: PostgreSQL and SQLite, detected from the URL
  • Drift detection (PostgreSQL): compare the live schema against the last known state and generate the migration that captures the changes
  • Schema analytics (PostgreSQL): diff any two schema versions, snapshots, or live databases
  • AI/script friendly: -json on every command, meaningful exit codes
  • Safe by construction: generated destructive statements come out commented; renames are flagged, never guessed

Installation

go install github.com/crgimenes/migration@latest

Or compile from source:

git clone https://github.com/crgimenes/migration.git
cd migration
go build -o migration

Usage

Since v5, running migration with no command opens the graphical interface; the terminal with explicit commands is the automation and AI interface.

migration [options] [command] [args]

Commands:
  (none)              open the GUI (default since v5)
  up [n]              run all (or n) pending migrations
  down [n]            revert all (or n) applied migrations
  status              list pending migrations
  snapshot            record the live schema (PostgreSQL)
  diff                show drift vs the last snapshot (exit 2 when found)
  capture [name]      turn drift into an up/down migration pair
  report <from> <to>  diff two points: snapshot version, `live`, or URL

Options:
  -url     database URL (or DATABASE_URL)
  -dir     migrations directory (or MIGRATIONS)
  -json    machine-readable JSON output
  -no-snapshot   skip the automatic snapshot after up/down
  -gui     open the GUI even when other parameters are present
  -debug   enable diagnostics (GUI devtools)
  -action  legacy action flag (or ACTION); prefer the positional form
GUI

migration alone opens a native-feeling window: a sidebar with the connected database always visible, and screens for Status, Drift, Report, and Connection. The connection form prefills from DATABASE_URL and MIGRATIONS when they are set.

Every operation is available on screen. Mutating actions (run pending migrations, revert the last one, capture drift) are two-step: the confirmation shows the exact SQL that will run, with a Copy SQL button, before anything touches the database. Destructive confirmations are red and never sit where Enter can hit them by accident.

Running migrations
export DATABASE_URL="postgres://user:password@localhost:5432/dbname?sslmode=disable"
export MIGRATIONS="./migrations"

migration status
migration up        # run everything pending
migration up 1      # run only one
migration down 1    # revert one

SQLite works the same way:

migration -url "sqlite:///path/to/database.db" -dir ./migrations up
migration -url "sqlite::memory:" -dir ./migrations status
Detecting manual changes (PostgreSQL)

People change databases directly. This tool turns those changes into migrations instead of letting them drift:

# After every successful `up`/`down` on PostgreSQL a schema snapshot is
# written to <migrations dir>/snapshots/NNN.json automatically. To
# record a baseline explicitly:
migration snapshot

# Someone runs DDL directly on the database. Later:
migration diff
# ● Drift detected: 2 changes
#   public.users
#     ● column_added public.users.email: text
#     ● index_added public.users.idx_users_email: CREATE INDEX ...
#   Σ 1 column added, 1 index added

# Turn the drift into a reviewable migration pair:
migration capture add_email
# writes 004_add_email.up.sql and 004_add_email.down.sql, registers
# version 4 as applied (the database already has these changes), and
# snapshots the new state.

Review the generated SQL before committing it. Statements that would destroy data (DROP TABLE, DROP COLUMN, DROP TYPE) are generated commented out with a warning; a drop+add pair that looks like a rename is flagged so you can rewrite it as ALTER ... RENAME yourself.

migration diff exits with code 2 when drift exists (0 = clean, 1 = error), so CI can fail a pipeline on unexpected manual changes:

migration -json diff | jq .changes
Schema analytics
migration report 3 7      # what changed between snapshot 3 and 7 (offline)
migration report 7 live   # what changed since snapshot 7 (-url database)
migration report "postgres://a/db1" "postgres://b/db2"   # two live databases
JSON output

Every command accepts -json. Examples:

migration -json status
# {"action":"status","count":2,"files":["..."],"ok":true}

migration -json diff
# {"action":"diff","snapshot":3,"drift":true,"changes":[{"kind":"column_added",...}],"ok":true}

Configuration

The GUI remembers connections in a Filo config file at the platform's own location:

platform path
macOS ~/Library/Application Support/migration/init.filo
Linux $XDG_CONFIG_HOME/migration/init.filo
Windows %AppData%\migration\init.filo

A migration_init.filo in the current directory takes precedence, for development. One form per connection:

; migration configuration
(connection "postgres://user:password@host:5432/db" "./migrations" "production")

The file is yours: the app only appends new connections and removes a single line when you ask; comments and anything else you write in it are never touched. On launch without parameters, the first saved connection is used.

The macOS location (not ~/.config) is deliberate: it is what the App Store sandbox remaps into the app container, so sandboxed builds work unchanged. assets/entitlements.plist carries the sandbox entitlements (network client, user-selected files) for store-ready signing.

Migration files

Files follow the naming convention:

001_create_users_table.up.sql
001_create_users_table.down.sql
002_add_email_index.up.sql
002_add_email_index.down.sql

The number prefix is the version. Each .up.sql needs a matching .down.sql that reverts it.

The schema_migrations table

The tool creates and manages a schema_migrations (version INTEGER PRIMARY KEY) table to track applied versions. It only ever touches this one table; it is excluded from snapshots, diffs, and reports.

Snapshots

<migrations dir>/snapshots/NNN.json holds the introspected schema as of migration version NNN: tables, columns, constraints and indexes (as canonical pg_get_constraintdef/pg_get_indexdef text), enums, and standalone sequences. Snapshots are plain JSON meant to be committed alongside the SQL files. Views, functions, and triggers are not modeled.

Exit codes

code meaning
0 success / no drift
1 error
2 drift found (diff only)

Development

go test -timeout 30s -count 1 ./...

PostgreSQL integration tests (introspection, capture round-trip) need a live server and skip when DATABASE_URL is not set:

docker run -d --rm --name migration-test-pg \
  -e POSTGRES_PASSWORD=migration -e POSTGRES_DB=migration_test \
  -p 55433:5432 postgres:15-alpine

DATABASE_URL='postgres://postgres:migration@localhost:55433/migration_test?sslmode=disable' \
  go test -timeout 120s -count 1 ./...

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
Package core runs SQL file migrations against PostgreSQL and SQLite, tracking applied versions in the schema_migrations table.
Package core runs SQL file migrations against PostgreSQL and SQLite, tracking applied versions in the schema_migrations table.
Package diff compares two introspected schema models and produces a typed change list.
Package diff compares two introspected schema models and produces a typed change list.
Package drift is the orchestration other tools import: compare the latest schema snapshot with the live database, and capture the difference as a reviewable up/down migration pair.
Package drift is the orchestration other tools import: compare the latest schema snapshot with the live database, and capture the difference as a reviewable up/down migration pair.
Package gen turns a diff change list into PostgreSQL DDL.
Package gen turns a diff change list into PostgreSQL DDL.
Package introspect reads the structure of a live PostgreSQL database into a comparable, JSON-serializable model.
Package introspect reads the structure of a live PostgreSQL database into a comparable, JSON-serializable model.
Package snapshot stores introspected schema models as versioned JSON files next to the migration SQL, so drift in the live database can be detected against the last known-good state.
Package snapshot stores introspected schema models as versioned JSON files next to the migration SQL, so drift in the live database can be detected against the last known-good state.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL