This cheatsheet provides a concise guide to using the golang-migrate/migrate library for database schema migrations. It covers installation, file structure, migration commands (up, down, force down), and best practices.
1. Overview
-
What is golang-migrate/migrate?
- A CLI tool and Go library for managing database schema migrations.
- Supports incremental, version-controlled, and reversible changes to database schemas.
- Compatible with databases like PostgreSQL, MySQL, SQLite, and more.
- Migrations are written as SQL files (or Go code for advanced cases).
-
Key Concepts
- Up Migration: Applies changes to evolve the schema (e.g., create tables, add columns).
- Down Migration: Reverts changes to roll back the schema (e.g., drop tables, remove columns).
- Force Down: Resolves issues with a "dirty" database by forcing a specific version.
2. Installation
Install the migrate CLI tool for your operating system.
Prerequisites
- Go installed (for Go-based CLI compilation, optional).
- A supported database (e.g., PostgreSQL, MySQL) with connection details.
Install via Package Managers
- MacOS (Homebrew):
brew install golang-migrate
- Linux (via curl):
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.17.1/migrate.linux-amd64.tar.gz | tar xvz
sudo mv migrate /usr/local/bin/
- Windows (Scoop):
scoop install migrate
- Verify Installation:
migrate -version
Install via Go (Optional)
If you prefer to build from source or use as a library:
go get -u github.com/golang-migrate/migrate/v4
3. File Structure
Organize migration files in a dedicated directory for version control and clarity.
Recommended Structure
project/
├── database/
│ ├── migrations/
│ │ ├── 202507120001_create_users_table.up.sql
│ │ ├── 202507120001_create_users_table.down.sql
│ │ ├── 202507120002_add_email_index.up.sql
│ │ ├── 202507120002_add_email_index.down.sql
│ └── schema.sql (optional: schema dump)
├── main.go
└── Makefile (optional: for migration shortcuts)
-
Naming Convention: Files are named
<timestamp>_<description>.<up/down>.sql.- Example:
202507120001_create_users_table.up.sqlfor creating a table. - Example:
202507120001_create_users_table.down.sqlfor dropping it.
- Example:
-
Directory Path: Typically
database/migrations/(relative to project root).
Example Migration Files
- 202507120001_create_users_table.up.sql:
-- Create users table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
- 202507120001_create_users_table.down.sql:
-- Drop users table
DROP TABLE IF EXISTS users;
- 202507120002_add_email_index.up.sql:
-- Add index on email column
CREATE INDEX idx_email ON users(email);
- 202507120002_add_email_index.down.sql:
-- Drop index on email column
DROP INDEX IF EXISTS idx_email;
4. Usage
Run migrations using the migrate CLI with a database connection string and migration path.
Basic Commands
- Create a New Migration:
migrate create -ext sql -dir database/migrations -seq create_table_name
-
-ext sql: Specifies SQL file extension. -
-dir: Path to migration directory. -
-seq: Generates a sequential timestamp. -
Example output: Creates
database/migrations/202507120003_create_table_name.up.sqland.down.sql.- Apply Migrations (Up):
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" -verbose up
- Applies all pending migrations in order.
-
-path: Directory containing migration files. -
-database: Database connection string (replace with your DB details). -
-verbose: Shows detailed output.- Revert Migrations (Down):
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" -verbose down
- Reverts the last applied migration.
-
Use
down Nto revert the lastNmigrations (e.g.,down 2).- Force Down (Fix Dirty Database):
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" force VERSION
- Use when a migration fails and marks the database as "dirty," preventing further migrations.
- Replace
VERSIONwith the desired migration version (e.g.,202507120001). - Caution: Ensure the database state matches the forced version to avoid inconsistencies.
-
Example: If migration
202507120002fails, fix the error in the.up.sqlfile, then run:
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" force 202507120001This sets the database to version
202507120001, clearing the dirty state.- Check Migration Status:
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" version
- Displays the current schema version.
Using with a Makefile (Optional)
Simplify commands with a Makefile:
# Makefile
DB_URL=postgresql://username:password@localhost:5432/dbname?sslmode=disable
migration_up:
migrate -path database/migrations/ -database "$(DB_URL)" -verbose up
migration_down:
migrate -path database/migrations/ -database "$(DB_URL)" -verbose down
migration_force:
migrate -path database/migrations/ -database "$(DB_URL)" force $(VERSION)
- Run:
make migration_up,make migration_down, ormake migration_force VERSION=202507120001.
5. Best Practices
- Version Control: Commit migration files to your repository (e.g., Git) for team collaboration.
- Test Migrations: Test migrations in a staging environment before applying to production.
-
Reversible Migrations: Always define
downmigrations to allow rollbacks. - Avoid Destructive Changes: Use non-destructive changes (e.g., add nullable columns) to minimize data loss risks.
- Backup Database: Always back up your database before running migrations.
-
Handle Dirty Databases:
- If a migration fails, check the error, fix the
.up.sqlor.down.sqlfile, and useforce VERSIONcautiously. - Verify the database state matches the forced version.
- If a migration fails, check the error, fix the
6. Common Issues and Solutions
-
Error: Dirty database version X. Fix and force version:
- Cause: A migration failed, leaving the database in a "dirty" state.
- Solution: Fix the problematic migration file, then run
migrate force Xto set the correct version.
- Migration order issues: Ensure migration files are applied sequentially based on timestamps.
- Connection errors: Verify the database connection string and ensure the database is running.
7. Example Workflow
- Create a migration:
migrate create -ext sql -dir database/migrations -seq add_posts_table
- Edit
database/migrations/202507120003_add_posts_table.up.sql:
-- Create posts table
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(id),
title VARCHAR(255) NOT NULL
);
- Edit
database/migrations/202507120003_add_posts_table.down.sql:
-- Drop posts table
DROP TABLE IF EXISTS posts;
- Apply the migration:
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" up
- Revert if needed:
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" down
-
If migration fails and database is dirty:
- Fix the error in the migration file.
- Force to the last successful version:
migrate -path database/migrations/ -database "postgresql://username:password@localhost:5432/dbname?sslmode=disable" force 202507120002
8. Additional Resources
- Official GitHub: golang-migrate/migrate
- Supported Databases: PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, and more.
- CLI Documentation: Run
migrate -helpfor full command details.
Top comments (0)