
Automatically generate database migrations from your GORM models by comparing them with the current database schema.
Features
- 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/integer are treated as equivalent)
Quick Start
1. Install
go get -u github.com/beesaferoot/gorm-migrate@latest
2. Set up environment
export DATABASE_URL="postgresql://user:pass@localhost:5432/your_db"
3. Create your migration binary
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)
}
}
4. Generate your model registry
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
}
5. Initialize and generate migrations
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
Usage
# 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 status
Example
Your 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
},
})
}
Environment Variables
| Variable |
Description |
Required |
DATABASE_URL |
PostgreSQL connection string |
Yes |
MIGRATIONS_PATH |
Path for migration files |
No (default: ./migrations) |
Testing
Run All Tests
make test
Run Tests with Coverage
go test -v -coverprofile=coverage.out ./tests/...
go tool cover -func=coverage.out
Run Specific Test Packages
# Run diff tests
go test ./tests/migration/diff/...
# Run command tests
go test ./tests/migration/...
# Run with verbose output
go test -v ./tests/...
Run Linters
make lint
Limitations
- 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.
License
MIT License - see LICENSE file for details.