Automatically generate database migrations from your GORM models by comparing them with the current database schema.
- Generate migrations automatically by comparing your GORM models with the database
- Only creates migrations when there are actual schema differences
- Handles case-insensitive table and column names correctly
- Reduces false positives through proper type normalization (e.g.,
int/bigint/integerare treated as equivalent)
go get -u github.com/beesaferoot/gorm-migrate@latestexport DATABASE_URL="postgresql://user:pass@localhost:5432/your_db"Create cmd/migration/main.go in your project:
package main
import (
"your-project/models" // Import your models package
"github.com/spf13/cobra"
"github.com/joho/godotenv"
"github.com/beesaferoot/gorm-migrate/migration"
"github.com/beesaferoot/gorm-migrate/migration/commands"
)
// Simple registry implementation
type MyModelRegistry struct{}
func (r *MyModelRegistry) GetModels() map[string]interface{} {
return models.ModelTypeRegistry // Your registry
}
func init() {
migration.GlobalModelRegistry = &MyModelRegistry{}
}
func main() {
_ = godotenv.Load() // optionally load environment file
rootCmd := &cobra.Command{
Use: "migration",
Short: "Database Migration Tool",
}
rootCmd.AddCommand(
commands.RegisterCmd(),
commands.InitCmd(),
commands.CreateCmd(),
commands.GenerateCmd(),
commands.UpCmd(),
commands.DownCmd(),
commands.StatusCmd(),
commands.HistoryCmd(),
commands.ValidateCmd(),
)
if err := rootCmd.Execute(); err != nil {
panic(err)
}
}Use the register command to automatically scan your models directory (e.g., models/) and generate a models_registry.go file.
go run cmd/migration/main.go register [path/to/models]This command creates a standard Go file that you can review and even edit if needed. It will look something like this:
package models
var ModelTypeRegistry = map[string]interface{}{
"User": User{},
"Post": Post{},
"Comment": Comment{},
// Add all your models here
}go run cmd/migration/main.go init
go run cmd/migration/main.go register [path/to/models]
go run cmd/migration/main.go generate init_db
go run cmd/migration/main.go up# Initialize migration system
go run cmd/migration/main.go init
# Generate migration from model changes
go run cmd/migration/main.go generate <name>
# Apply migrations
go run cmd/migration/main.go up
# Rollback last migration
go run cmd/migration/main.go down
# Check status
go run cmd/migration/main.go statusYour GORM model:
type User struct {
gorm.Model
Name string
Email string `gorm:"uniqueIndex"`
}Generated migration:
package migrations
import (
"github.com/beesaferoot/gorm-migrate/migration"
"gorm.io/gorm"
"time"
)
func init() {
migration.RegisterMigration(&migration.Migration{
Version: "20250620232804",
Name: "init_db",
CreatedAt: time.Now(),
Up: func(db *gorm.DB) error {
if err := db.Exec(`CREATE TABLE "users" (
id BIGSERIAL PRIMARY KEY,
created_at timestamp,
updated_at timestamp,
deleted_at timestamp,
name varchar(255),
email varchar(255)
);`).Error; err != nil {
return err
}
if err := db.Exec(`CREATE UNIQUE INDEX idx_users_email ON "users"(email);`).Error; err != nil {
return err
}
return nil
},
Down: func(db *gorm.DB) error {
if err := db.Exec(`DROP TABLE IF EXISTS "users";`).Error; err != nil {
return err
}
return nil
},
})
}| Variable | Description | Required |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | Yes |
MIGRATIONS_PATH |
Path for migration files | No (default: ./migrations) |
make testgo test -v -coverprofile=coverage.out ./tests/...
go tool cover -func=coverage.out# Run diff tests
go test ./tests/migration/diff/...
# Run command tests
go test ./tests/migration/...
# Run with verbose output
go test -v ./tests/...make lint- Schema comparison is model-driven.
- Only columns present in your Go models are considered for schema diffs. Any manual changes to the database schema that are not reflected in your models will not be detected.
If you require support for these features, please open an issue or contribute to the project.
MIT License - see LICENSE file for details.