A Go-first database migration tool with a Django-style workflow. Define your schema in YAML, generate type-safe Go migration files, and run them with a compiled binary that embeds every migration your project has ever had.
- 🔒 Type-safe: Migrations are Go code — caught by the compiler, not at runtime
- 📦 Self-contained binary: One compiled binary knows all migrations, their dependencies, and their SQL
- 🗄️ Database-agnostic schema: Write YAML once, deploy to PostgreSQL, MySQL, SQLite, or SQL Server
- 🔀 DAG-based ordering: Migrations form a dependency graph so parallel branches merge cleanly
- 🔄 Auto change detection: Diff YAML schemas, generate only what changed
⚠️ Safe destructive ops: Field removals, table drops, and renames require explicit review- 🔧 Zero runtime dependency: The compiled binary has no runtime dependency on makemigrations itself
go install github.com/ocomsoft/makemigrations@latestcd your-project
makemigrations initThis creates:
your-project/
└── migrations/
├── main.go ← compiled binary entry point
└── go.mod ← dedicated migrations module
If *.sql Goose files already exist in migrations/, they are automatically converted to Go migrations. See Upgrading from Goose.
schema/schema.yaml:
tables:
- name: users
fields:
- name: id
type: uuid
primary_key: true
default: new_uuid
- name: email
type: varchar
length: 255
nullable: false
- name: created_at
type: timestamp
auto_create: true
- name: posts
fields:
- name: id
type: uuid
primary_key: true
default: new_uuid
- name: title
type: varchar
length: 200
nullable: false
- name: user_id
type: foreign_key
foreign_key:
table: users
on_delete: CASCADEmakemigrations makemigrations --name "initial"
# Creates: migrations/0001_initial.goexport DATABASE_URL="postgresql://user:pass@localhost/mydb"
makemigrations migrate upmakemigrations migrate compiles the migration binary automatically and runs it with the correct Go workspace settings. No manual go build required.
# 1. Edit your YAML schema
vim schema/schema.yaml
# 2. Preview what will be generated
makemigrations makemigrations --dry-run
# 3. Generate the migration
makemigrations makemigrations --name "add user preferences"
# Creates: migrations/0004_add_user_preferences.go
# 4. Review the SQL before applying
makemigrations migrate showsql
# 5. Apply
makemigrations migrate up
# 6. Verify
makemigrations migrate statusmakemigrations migrate compiles and runs the migration binary. All arguments are forwarded:
makemigrations migrate up # apply all pending
makemigrations migrate up --to 0003_add_index # apply up to a specific migration
makemigrations migrate down # roll back one
makemigrations migrate down --steps 3 # roll back multiple
makemigrations migrate status # show applied / pending
makemigrations migrate showsql # print SQL without running it
makemigrations migrate fake 0001_initial # mark applied without running SQL
makemigrations migrate dag # show migration dependency graph
makemigrations migrate --verbose up # show build outputyour-project/
├── schema/
│ └── schema.yaml ← your YAML schema definition
├── migrations/
│ ├── main.go ← binary entry point (generated by init)
│ ├── go.mod ← dedicated module (generated by init)
│ ├── 0001_initial.go ← migration files (generated by makemigrations)
│ ├── 0002_add_posts.go
│ └── 0003_add_index.go
├── go.mod
└── main.go
| Database | Status | Notes |
|---|---|---|
| PostgreSQL | ✅ Full | UUID, JSONB, arrays, advanced types |
| MySQL | ✅ Supported | JSON, AUTO_INCREMENT, InnoDB |
| SQLite | ✅ Supported | Simplified types, basic constraints |
| SQL Server | ✅ Supported | UNIQUEIDENTIFIER, NVARCHAR, BIT |
| Amazon Redshift | ✅ Provider ready | SUPER JSON, IDENTITY sequences |
| ClickHouse | ✅ Provider ready | MergeTree engine, Nullable types |
| TiDB | ✅ Provider ready | MySQL-compatible, distributed |
| Vertica | ✅ Provider ready | Columnar analytics |
| YDB (Yandex) | ✅ Provider ready | Optional, native JSON |
| Turso | ✅ Provider ready | Edge SQLite |
| StarRocks | ✅ Provider ready | MPP analytics, OLAP |
| Aurora DSQL | ✅ Provider ready | AWS serverless, PostgreSQL-compatible |
PostgreSQL has been tested against real database instances. All other providers have comprehensive unit tests but may need additional validation for production.
When a field removal, table drop, or rename is detected, makemigrations prompts before generating:
⚠ Destructive operation detected: field_removed on "users" (field: "legacy_col")
1) Generate — include SQL in migration
2) Review — include with // REVIEW comment
3) Omit — skip SQL; schema state still advances (SchemaOnly)
4) Exit — cancel migration generation
5) All — generate all remaining destructive ops without prompting
Choice [1-5]:
When two developers generate migrations concurrently the DAG develops branches:
0001_initial
├── 0002_add_messaging (developer A)
└── 0003_add_payments (developer B)
Resolve with a merge migration:
makemigrations makemigrations --merge
# Creates: migrations/0004_merge_0002_add_messaging_and_0003_add_payments.goRun makemigrations init in a directory containing Goose *.sql files and they are converted automatically:
# migrations/ has 00001_initial.sql, 00002_add_phone.sql ...
makemigrations init
# Detected 2 Goose SQL migration(s) — running migrate-to-go...
# ✓ Created migrations/0001_initial.go
# ✓ Created migrations/0002_add_phone.go
# ✓ Created migrations/main.go
# ✓ Created migrations/go.mod
# ✓ Created migrations/0003_schema_state.go (schema-state bootstrap)
# ✗ Deleted migrations/00001_initial.sql
# ✗ Deleted migrations/00002_add_phone.sqlIf the schema is already applied to your database, fake the historical migrations:
makemigrations migrate fake 0001_initial
makemigrations migrate fake 0002_add_phone
makemigrations migrate statusOr use the dedicated conversion command for more control:
makemigrations migrate-to-go --dir migrations/The compiled binary reads connection details from migrations/main.go. The generated file uses DATABASE_URL and DB_TYPE:
export DATABASE_URL="postgresql://user:pass@localhost/mydb"
export DB_TYPE=postgresql # optional, defaults to postgresqlDB_HOST, DB_PORT, DB_USER etc. can be added by editing migrations/main.go — see the Manual Build Guide.
migrations/makemigrations.config.yaml:
database:
type: postgresql
migration:
directory: migrations
include_down_sql: true
output:
verbose: falseSee the Configuration Guide for complete options.
- Installation Guide
- Schema Format Guide — complete YAML schema reference
- Configuration Guide
- Manual Build Guide — GOWORK/GOTOOLCHAIN details for CI/CD
| Command | Description |
|---|---|
| init | Bootstrap the migrations/ directory |
| makemigrations | Generate .go migration files from YAML schema |
| migrate | Build and run the compiled migration binary |
| migrate-to-go | Convert existing Goose SQL migrations to Go |
| struct2schema | Generate YAML schemas from Go structs |
| dump_sql | Preview generated SQL from schemas |
| db2schema | Reverse-engineer schema from existing database |
For projects that predate the Go migration framework, the original YAML→SQL→Goose workflow is still supported:
makemigrations init --sql # create SQL-based project
makemigrations makemigrations_sql # generate Goose-compatible SQL files
makemigrations goose up # apply via Goose- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Add tests for new functionality
- Ensure all tests pass:
go test ./... - Submit a pull request
MIT License — see LICENSE file for details.
Ready to get started? Run makemigrations init in your project directory.