Quick Start
Create and run your first database migration with go-migration in minutes.
Quick Start
This guide walks you through creating and running your first migration with go-migration v1.0.0. By the end, you'll have a users table in your database.
Initialize Your Project
The fastest way to get started is with go-migration init. This command scaffolds all the directories and files you need:
go-migration initThis creates:
database/migrations/,database/seeders/,database/factories/directoriescmd/migrator/main.go— entry point withmigrator.Run()migration.json— config file with environment variable placeholders (JSON format)
The command auto-detects your module path from go.mod. See the CLI Reference for flags like --module and --force.
If you prefer to set up manually, you can skip this step and create the config file and directories yourself — see the steps below.
Create a Config File
If you ran go-migration init, a migration.json was already created in your project root with sensible defaults. Open it and fill in your database credentials:
{
"default": "postgres",
"connections": {
"postgres": {
"driver": "postgres",
"host": "${DB_HOST}",
"port": 5432,
"database": "${DB_NAME}",
"username": "${DB_USER}",
"password": "${DB_PASSWORD}",
"sslmode": "disable"
}
},
"migration_dir": "database/migrations",
"seeder_dir": "database/seeders",
"factory_dir": "database/factories",
"migration_table": "migrations",
"log_level": "info"
}If you prefer YAML, create a go-migration.yaml manually. Note: YAML format is deprecated since v1.0.0 and will show a deprecation warning when loaded.
default: postgres
connections:
postgres:
driver: postgres
host: ${DB_HOST}
port: 5432
database: ${DB_NAME}
username: ${DB_USER}
password: ${DB_PASSWORD}
sslmode: disable
migration_dir: database/migrations
seeder_dir: database/seeders
factory_dir: database/factories
migration_table: migrations
log_level: info${VAR_NAME} placeholders are replaced with environment variable values at load time. See Configuration for all supported fields.
Define a Migration
Create a migration file with an init() function for auto-registration, plus Up and Down methods:
package migrations
import (
"github.com/gopackx/go-migration/migrator"
"github.com/gopackx/go-migration/schema"
)
func init() {
migrator.AutoRegister("2025_01_15_143022_1234_create_users_table", &CreateUsersTable{})
}
type CreateUsersTable struct{}
func (m *CreateUsersTable) Up(s *schema.Builder) error {
return s.Create("users", func(bp *schema.Blueprint) {
bp.ID()
bp.String("name", 255)
bp.String("email", 255).Unique()
bp.Boolean("active").Default(true)
bp.Timestamps()
})
}
func (m *CreateUsersTable) Down(s *schema.Builder) error {
return s.Drop("users")
}The init() function registers the migration automatically when the package is imported. The Up method creates the table, and Down reverses it.
Migration filenames in v1.0.0 use the format YYYY_MM_DD_HHMMSS_RRRR_description.go, where RRRR is a random 4-digit number to prevent timestamp collisions. The make:migration command generates this automatically. The old format (YYYYMMDDHHMMSS_description.go) is still supported.
Set Up and Run
migrator.Run() is the all-in-one CLI runner introduced in v1.0.0. It handles config loading, database connection, auto-discovery of migrations and seeders, grammar auto-resolution, and command dispatch — all in a single call.
package main
import (
"github.com/gopackx/go-migration/migrator"
_ "your-project/database/migrations" // blank import triggers init() registration
_ "your-project/database/seeders" // blank import triggers seeder init() registration
)
func main() {
migrator.Run()
}That's it. migrator.Run() will:
- Parse CLI arguments (
migrate,db:seed,migrate:fresh, etc.) - Load
migration.json(with${ENV}interpolation, falls back togo-migration.yaml) - Open a database connection
- Auto-discover all registered migrations and seeders
- Resolve the correct grammar from the driver name
- Execute the requested command
If you need more control, you can set up the migrator manually:
package main
import (
"database/sql"
"log"
_ "github.com/lib/pq" // PostgreSQL driver
"github.com/gopackx/go-migration/migrator"
_ "your-project/database/migrations" // blank import triggers init() registration
)
func main() {
db, err := sql.Open("postgres", "postgres://user:password@localhost:5432/mydb?sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
m := migrator.New(db, migrator.WithAutoDiscover())
if err := m.Up(); err != nil {
log.Fatal(err)
}
log.Println("Migrations completed successfully!")
}The blank import _ "your-project/database/migrations" triggers all init() functions, and WithAutoDiscover() loads them into the migrator.
Run It
# With migrator.Run() — use CLI commands directly
go run main.go migrate
# Or run all pending migrations with manual setup
go run main.gogo-migration will:
- Create a
migrationstracking table (if it doesn't exist) - Check which migrations have already run
- Execute the
Upmethod of any pending migrations - Record the migration in the tracking table with a batch number
Replace the connection string or environment variables with your actual database credentials. The example above uses PostgreSQL — see Database Grammars for MySQL and SQLite setup.
Using migrator.Run()
With migrator.Run(), your binary becomes a full CLI tool. All standard commands are available:
go run main.go migrate # Run pending migrations
go run main.go migrate --seed # Run pending migrations + seeders
go run main.go migrate:rollback # Roll back last batch
go run main.go migrate:fresh # Drop all tables + re-migrate
go run main.go migrate:refresh # Reset + re-migrate
go run main.go migrate:refresh --seed # Reset + re-migrate + seed
go run main.go migrate:status # Show migration status
go run main.go db:seed # Run all seeders
go run main.go db:seed --class=UserSeeder # Run specific seeder
go run main.go db:seed --tag=core # Run seeders by tag
go run main.go make:migration create_posts # Scaffold a migration filemigrator.Run() uses smart command classification — commands like version, help, and make:* skip database setup entirely, so they work even without a valid database connection.
New in v1.0.0: The --seed flag on migrate and migrate:refresh, and the --tag flag on db:seed for running seeders by tag. See the CLI Reference for all available flags.
Using a Different Database
go-migration supports PostgreSQL, MySQL, and SQLite. With migrator.Run(), the grammar is auto-resolved from the driver field in your config file — no manual grammar selection needed.
For manual setup, swap the driver import and grammar:
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"github.com/gopackx/go-migration/migrator"
"github.com/gopackx/go-migration/schema/grammars"
_ "your-project/database/migrations"
)
func main() {
db, _ := sql.Open("mysql", "user:password@tcp(localhost:3306)/mydb")
m := migrator.New(db,
migrator.WithGrammar(&grammars.MySQLGrammar{}),
migrator.WithAutoDiscover(),
)
// Run as before...
}import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"github.com/gopackx/go-migration/migrator"
"github.com/gopackx/go-migration/schema/grammars"
_ "your-project/database/migrations"
)
func main() {
db, _ := sql.Open("sqlite3", "./app.db")
m := migrator.New(db,
migrator.WithGrammar(&grammars.SQLiteGrammar{}),
migrator.WithAutoDiscover(),
)
// Run as before...
}Rolling Back
To undo the last batch of migrations:
// Roll back the last batch
if err := m.Rollback(0); err != nil {
log.Fatal(err)
}This calls the Down method on each migration in the last batch, in reverse order.
What's Next?
- Building Your CLI — build a project binary to run migrations, seeders, and factories (like Laravel Artisan)
- Project Structure — recommended directory layout
- Migrations — deep dive into defining and managing migrations
- Schema Builder — learn the full table and column API