Interface-driven migrations for Go.
I Migrate is an interface-driven approach to managing database migrations. It was created out of a need for a migration tool that can be used in a Go project that doesn't conform to database/sql, and can execute migrations embedded in a single binary.
This project aims to fulfill the following needs:
- Migrations written in pure SQL, stored in flat files.
- CLI runner for up, down, redo, rollback, status, dry-run, etc.
- CLI template generator for timestamp-prefixed migrations.
fs.FSsupport, allowing migration files to be embedded via//go:embed.- Database driver agnostic via a sql Exec interface.
- No config files. (But config in code)
- All public API methods return errors (no panics).
- Dry-run mode to preview SQL without executing it.
For projects using database/sql, use the provided SQLDB adapter:
db, err := sql.Open("sqlite3", "db.sqlite3")
if err != nil {
log.Fatal(err)
}
defer db.Close()
executor := imigrate.NewSQLDB(db)
migrator := imigrate.NewIMigrator(executor, os.DirFS("."))
imigrate.CLI(migrator)//go:embed migrations
var migrationsFS embed.FS
func main() {
db, _ := sql.Open("sqlite3", "app.db")
executor := imigrate.NewSQLDB(db)
migrator := imigrate.NewIMigrator(executor, migrationsFS)
// WriteDirname tells Create where to write new files on disk,
// since the embed.FS is read-only.
migrator.WriteDirname = "internal/db/migrations"
imigrate.CLI(migrator)
}If your database driver does not conform to database/sql, implement the Executor interface:
type Executor interface {
Exec(query string, args ...interface{}) (sql.Result, error)
GetVersions(query string, args ...interface{}) ([]int64, error)
}All public API methods return errors:
// Run all pending migrations
err := migrator.Up(-1, 0)
// Run a specific number of migrations
err = migrator.Up(2, 0)
// Run a specific version
err = migrator.Up(-1, 1610069160)
// Roll back
err = migrator.Down(-1, 0)
// Preview what Up would do
err = migrator.DryRun(-1, 0)Use CLIWithArgs when you need to control the argument parsing:
args := []string{"up", "-steps=1"}
err := imigrate.CLIWithArgs(migrator, args)CLI(migrator) is a convenience wrapper that passes os.Args[1:].
migrator := imigrate.NewIMigrator(executor, fsys)
// Set a separate directory for writing new migration files
migrator.WriteDirname = "internal/db/migrations"
// Silence migration output
migrator.Logger = imigrate.DiscardLogger
// Or provide your own logger
migrator.Logger = log.New(os.Stderr, "[migrate] ", log.LstdFlags)Example CLI usage for a tool named "migrate":
migrate create create_users_table
migrate up
migrate up -steps=1
migrate up -version=1610069160
migrate down
migrate down -steps=1
migrate redo
migrate redo -steps=2
migrate rollback
migrate rollback -steps=3
migrate status
migrate dry-run
migrate dry-run -steps=2
migrate dry-run -version=1610069160All commands accept a -silent flag to suppress output.