Skip to content

basant-rai/gomigrate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gomigrate

Auto-generate Postgres migration files from Go structs.

No ORM required. Works with any raw SQL setup (pgx, sqlx, database/sql).

How it works

Go struct changes → gomigrate detects diff → generates .up.sql + .down.sql

Install

go install github.com/basant-rai/gomigrate/cmd/gomigrate@latest

Quick Start

1. Register your models in cmd/migrate/main.go

m := migrator.New(db, "migrations")
m.Register(&User{}, "users")
m.Register(&Card{}, "card_relationships")
m.Register(&FuelTransaction{}, "fuel_transactions")

2. Check for changes

export DATABASE_URL="postgresql://<USERNAME>:<PASSWORD>@<HOST>:<PORT>/<DB_NAME>"
gomigrate --diff

Output:

⚠️  Detected 2 change(s):

  + ADD    [users] profile_pic TEXT
  + ADD    [users] avatar_url TEXT

3. Generate migration

gomigrate --generate add_profile_pic_to_users

Output:

✅ Generated migration files:
   migrations/000006_add_profile_pic_to_users.up.sql
   migrations/000006_add_profile_pic_to_users.down.sql

Run: make migrate-up

4. Apply migration

make migrate-up

Generated SQL example

000006_add_profile_pic_to_users.up.sql:

-- Auto-generated by gomigrate
-- Generated at: 2024-01-15 10:30:00

-- Alter table: users
ALTER TABLE users ADD COLUMN IF NOT EXISTS profile_pic TEXT NOT NULL DEFAULT '';
ALTER TABLE users ADD COLUMN IF NOT EXISTS avatar_url TEXT NOT NULL DEFAULT '';

SELECT '✅ 000006_add_profile_pic_to_users applied' AS status;

000006_add_profile_pic_to_users.down.sql:

-- Auto-generated by gomigrate
-- Generated at: 2024-01-15 10:30:00

-- Revert table: users
ALTER TABLE users DROP COLUMN IF EXISTS profile_pic;
ALTER TABLE users DROP COLUMN IF EXISTS avatar_url;

SELECT '✅ 000006_add_profile_pic_to_users rolled back' AS status;

Struct tags

gomigrate reads db tags from your structs:

type User struct {
    domain.Base                                    // id, created_at, updated_at (skipped)
    Name     string     `db:"name"`               // TEXT NOT NULL DEFAULT ''
    Age      int64      `db:"age"`                // BIGINT NOT NULL DEFAULT 0
    Bio      *string    `db:"bio"`                // TEXT (nullable)
    IsActive bool       `db:"is_active"`          // BOOLEAN NOT NULL DEFAULT false
    Tags     []string   `db:"tags"`               // TEXT[]
}

Type mapping

Go type SQL type
string TEXT
int / int32 INTEGER
int64 BIGINT
float64 FLOAT
bool BOOLEAN
time.Time TIMESTAMPTZ
uuid.UUID UUID
[]string TEXT[]
[]byte BYTEA
*T (pointer) T (nullable)

Makefile integration

Add to your Makefile:

migrate-diff:
    gomigrate --diff

migrate-generate:
    @if [ -z "$(NAME)" ]; then echo "Usage: make migrate-generate NAME=your_name"; exit 1; fi
    gomigrate --generate $(NAME)

Usage:

make migrate-diff
make migrate-generate NAME=add_profile_pic
make migrate-up

Limitations

  • Does not detect column drops (safe by design — dropping is dangerous)
  • Does not detect index changes
  • Does not detect constraint changes
  • New tables are fully generated, existing tables only get ALTER statements

Contributing

PRs welcome! This fills a real gap in the Go ecosystem.

Packages

 
 
 

Contributors

Languages