go-migrate-lite
A tiny, dependency-light SQL migration runner for Postgres, written in Go.
It runs *.sql files in lexical order, tracks applied versions in schema_migrations, and works both as a CLI tool and as a Go library (including with embed.FS).
Features
- Runs migrations in filename order (e.g.,
001_init.sql, 002_add_index.sql).
- Tracks applied versions in
schema_migrations — safe to run repeatedly.
- Accepts any
fs.FS: filesystem path, embed.FS, or custom.
- Works with PostgreSQL and TimescaleDB.
CLI
Run directly
export DATABASE_URL="postgres://user:pass@localhost:5432/mydb?sslmode=disable"
export MIGRATIONS_DIR=./migrations
go run github.com/jsness/go-migrate-lite/cmd/migrate-lite@latest
Build binary
go install github.com/jsness/go-migrate-lite/cmd/migrate-lite@latest
migrate-lite
Environment
| Variable |
Required |
Default |
Description |
DATABASE_URL |
yes |
— |
Postgres connection string |
MIGRATIONS_DIR |
no |
migrations |
Path to migration files |
Library
Import the package to run migrations at application startup — useful with embed.FS so no external CLI or migration directory is needed at runtime.
import (
"embed"
migratelite "github.com/jsness/go-migrate-lite"
)
//go:embed migrations/*.sql
var migrationsFS embed.FS
// In main, after connecting to the database:
if err := migratelite.Run(ctx, pool, migrationsFS); err != nil {
log.Fatalf("migrations: %v", err)
}
Run applies any pending .sql files from the given fs.FS in lexical order and records each applied version in schema_migrations. It is idempotent — already-applied versions are skipped.
The version key is the numeric prefix of the filename (e.g. "001" from 001_init.sql), matching the CLI, so both can run against the same database without conflict.
Migration Rules
- Filenames must start with a numeric version prefix followed by an underscore (e.g.
001_init.sql).
- Files are applied in lexical order.
- Each migration is applied exactly once.
migrations/
001_init.sql
002_add_index.sql
License
MIT