README
ΒΆ
gomigratex
A lightweight, production-ready MySQL migration tool for Go applications with support for both CLI usage and library integration.
Overview
gomigratex is designed to help you manage database schema changes in a safe, reliable, and version-controlled manner. Whether you're building a microservice, a monolith, or a distributed system, gomigratex provides the tools you need to handle database migrations with confidence.
Key Features
- π Dual Interface - Use as a standalone CLI tool or embed as a library in your Go applications
- ποΈ MySQL Optimized - Built specifically for MySQL with proper connection handling and syntax support
- π¦ Embedded Migrations - Bundle SQL migration files directly into your application binary using Go's
embedpackage - π Checksum Validation - Automatically detect drift between migration files and database records
- π Advisory Locking - Prevent concurrent migrations with MySQL's advisory lock mechanism
- βͺ Rollback Support - Full support for down migrations with proper ordering
- π Baseline Support - Mark existing database schemas as migrated without applying changes
- π Structured Logging - JSON output for easy integration with logging and monitoring systems
- π§ͺ Dry Run Mode - Preview migration plans without executing them
- β Production Ready - Comprehensive test coverage and battle-tested in production environments
Table of Contents
- Installation
- Quick Start
- CLI Usage
- Library Usage
- Migration Files
- Configuration
- Advanced Topics
- Best Practices
- Troubleshooting
- Contributing
- License
Installation
CLI Tool
Option 1: Download Pre-Built Binary (Recommended)
Download the latest release from GitHub Releases:
Linux:
wget https://github.com/mirajehossain/gomigratex/releases/latest/download/migratex-linux
chmod +x migratex-linux
sudo mv migratex-linux /usr/local/bin/migratex
macOS (Intel):
wget https://github.com/mirajehossain/gomigratex/releases/latest/download/migratex-darwin
chmod +x migratex-darwin
sudo mv migratex-darwin /usr/local/bin/migratex
macOS (Apple Silicon):
wget https://github.com/mirajehossain/gomigratex/releases/latest/download/migratex-darwin-arm64
chmod +x migratex-darwin-arm64
sudo mv migratex-darwin-arm64 /usr/local/bin/migratex
Windows: Download migratex-windows.exe and add to your PATH.
Verify installation:
migratex -v
# Output: gomigratex v1.0.0
Option 2: Install via go install
Install the latest version directly from GitHub:
go install github.com/mirajehossain/gomigratex/cmd/migratex@latest
This will automatically use the latest release version.
Library
Add to your Go project:
go get github.com/mirajehossain/gomigratex@latest
Use a specific version:
go get github.com/mirajehossain/gomigratex@v1.0.0
Quick Start
Step 1: Create Migration Files
Create your first migration using the CLI:
migratex create add_users_table --dir ./migrations
This generates two files:
20250109120000_add_users_table.up.sql- Forward migration20250109120000_add_users_table.down.sql- Rollback migration
Step 2: Write Your SQL
20250109120000_add_users_table.up.sql:
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_email (email),
INDEX idx_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
20250109120000_add_users_table.down.sql:
DROP TABLE IF EXISTS users;
Step 3: Apply Migrations
Set up your database connection and apply migrations:
export DB_DSN="user:password@tcp(localhost:3306)/mydb?parseTime=true&multiStatements=true"
# Apply all pending migrations
migratex up --dsn "$DB_DSN" --dir ./migrations
# Check migration status
migratex status --dsn "$DB_DSN" --dir ./migrations
Output:
Applied 1 migration(s) successfully
β 20250109120000_add_users_table.up.sql
CLI Usage
Available Commands
| Command | Description |
|---|---|
up |
Apply all pending migrations |
down <n> |
Rollback last N migrations (use all to rollback everything) |
status |
Display migration status (applied/pending) |
create <name> |
Create a new migration file pair |
repair |
Update checksums after manual file edits |
force <version> |
Mark specific migrations as applied (baseline) |
version, -v, --version |
Display version information |
Global Flags
| Flag | Environment Variable | Description | Default |
|---|---|---|---|
--dsn |
DB_DSN |
MySQL connection string | - |
--dir |
MIGRATIONS_DIR |
Directory containing migration files | ./migrations |
--table |
MIGRATIONS_TABLE |
Name of migrations tracking table | schema_migrations |
--json |
- | Output in JSON format | false |
--dry-run |
- | Show execution plan without applying | false |
--verbose |
- | Enable detailed per-migration logging | false |
--lock-timeout |
LOCK_TIMEOUT_SEC |
Advisory lock timeout in seconds | 30 |
Command Examples
Apply all pending migrations:
migratex up --dsn "$DB_DSN" --dir ./migrations
Apply with verbose output:
migratex up --dsn "$DB_DSN" --dir ./migrations --verbose
Preview migrations without applying (dry run):
migratex up --dsn "$DB_DSN" --dir ./migrations --dry-run
Get JSON output for automation:
migratex status --dsn "$DB_DSN" --dir ./migrations --json
Create a new migration:
migratex create add_user_indexes --dir ./migrations
Rollback the last migration:
migratex down 1 --dsn "$DB_DSN" --dir ./migrations
Rollback all migrations:
migratex down all --dsn "$DB_DSN" --dir ./migrations
Baseline an existing database:
# Mark all migrations up to version 20250109120000 as applied
migratex force 20250109120000 --dsn "$DB_DSN" --dir ./migrations
Repair checksums after manual edits:
migratex repair --dsn "$DB_DSN" --dir ./migrations
Using Configuration Files
Create migratex.yaml:
dsn: "user:password@tcp(localhost:3306)/mydb?parseTime=true&multiStatements=true"
dir: "./migrations"
table: "schema_migrations"
lock_timeout_sec: 30
applied_by: "deployment-system"
verbose: true
json: false
Use the configuration file:
migratex up --config migratex.yaml
Library Usage
Basic Integration
Integrate gomigratex directly into your Go application:
package main
import (
"context"
"database/sql"
"log"
"github.com/mirajehossain/gomigratex/internal/db"
"github.com/mirajehossain/gomigratex/internal/migrator"
)
func main() {
ctx := context.Background()
// Connect to MySQL database
dsn := "user:password@tcp(localhost:3306)/mydb?parseTime=true&multiStatements=true"
database, err := db.OpenMySQL(dsn)
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
defer database.Close()
// Create migration runner
runner := migrator.NewRunner(database, "schema_migrations", "myapp")
// Ensure migration table exists
if err := runner.Ensure(ctx); err != nil {
log.Fatalf("Failed to create migration table: %v", err)
}
// Set up file source
src := migrator.FileSource{
RootDir: "./migrations",
}
// Discover and plan migrations
plan, err := migrator.DiscoverAndPlan(ctx, src, runner.Storage)
if err != nil {
log.Fatalf("Failed to discover migrations: %v", err)
}
// Apply pending migrations
if len(plan.Pending) > 0 {
log.Printf("Applying %d pending migration(s)...", len(plan.Pending))
applied, err := runner.ApplyUp(ctx, plan.Pending, false, nil)
if err != nil {
log.Fatalf("Migration failed: %v", err)
}
log.Printf("Successfully applied %d migration(s)", len(applied))
} else {
log.Println("No pending migrations")
}
}
Embedded Migrations
Bundle migrations directly into your application binary:
package main
import (
"context"
"embed"
"log"
"github.com/mirajehossain/gomigratex/internal/db"
"github.com/mirajehossain/gomigratex/internal/migrator"
)
//go:embed migrations/*.sql
var migrationFS embed.FS
func main() {
ctx := context.Background()
// Connect to database
dsn := "user:password@tcp(localhost:3306)/mydb?parseTime=true&multiStatements=true"
database, err := db.OpenMySQL(dsn)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer database.Close()
// Create runner
runner := migrator.NewRunner(database, "schema_migrations", "myapp")
if err := runner.Ensure(ctx); err != nil {
log.Fatalf("Failed to ensure schema: %v", err)
}
// Use embedded filesystem
src := migrator.FileSource{
FS: migrationFS,
RootDir: "migrations",
Embedded: true,
}
// Plan and apply
plan, err := migrator.DiscoverAndPlan(ctx, src, runner.Storage)
if err != nil {
log.Fatalf("Failed to plan: %v", err)
}
if len(plan.Pending) > 0 {
applied, err := runner.ApplyUp(ctx, plan.Pending, false, nil)
if err != nil {
log.Fatalf("Migration failed: %v", err)
}
log.Printf("Applied %d migration(s)", len(applied))
}
}
Advanced: Custom Logger Integration
Integrate with your existing logging infrastructure:
package main
import (
"context"
"log/slog"
"os"
"github.com/mirajehossain/gomigratex/internal/db"
"github.com/mirajehossain/gomigratex/internal/migrator"
)
func main() {
ctx := context.Background()
// Set up structured logger
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
}))
database, err := db.OpenMySQL(os.Getenv("DB_DSN"))
if err != nil {
logger.Error("database connection failed", "error", err)
os.Exit(1)
}
defer database.Close()
runner := migrator.NewRunner(database, "schema_migrations", "myapp")
// Custom callback for migration events
callback := func(version, name, direction string, success bool, duration int64) {
logger.Info("migration completed",
"version", version,
"name", name,
"direction", direction,
"success", success,
"duration_ms", duration,
)
}
if err := runner.Ensure(ctx); err != nil {
logger.Error("ensure failed", "error", err)
os.Exit(1)
}
src := migrator.FileSource{RootDir: "./migrations"}
plan, err := migrator.DiscoverAndPlan(ctx, src, runner.Storage)
if err != nil {
logger.Error("plan failed", "error", err)
os.Exit(1)
}
if len(plan.Pending) > 0 {
applied, err := runner.ApplyUp(ctx, plan.Pending, false, callback)
if err != nil {
logger.Error("migration failed", "error", err)
os.Exit(1)
}
logger.Info("migrations completed", "count", len(applied))
}
}
Migration Files
Naming Convention
Migration files must follow this strict naming pattern:
{timestamp}_{description}.{direction}.sql
Components:
timestamp: 14-digit timestamp in formatYYYYMMDDHHmmssdescription: Lowercase descriptive name with underscoresdirection: Eitherup(forward) ordown(rollback)- Extension: Always
.sql
Examples:
20250109120000_create_users_table.up.sql
20250109120000_create_users_table.down.sql
20250109120100_add_user_email_index.up.sql
20250109120100_add_user_email_index.down.sql
20250109120200_add_posts_table.up.sql
20250109120200_add_posts_table.down.sql
Migration File Structure
Forward Migration (up):
-- 20250109120000_create_users_table.up.sql
-- Create users table with proper indexes
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) NOT NULL,
username VARCHAR(100) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uniq_email (email),
INDEX idx_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Rollback Migration (down):
-- 20250109120000_create_users_table.down.sql
-- Drop users table
DROP TABLE IF EXISTS users;
Multi-Statement Migrations
For complex migrations with multiple statements, ensure multiStatements=true is in your DSN:
-- 20250109120100_add_user_profiles.up.sql
CREATE TABLE user_profiles (
user_id BIGINT PRIMARY KEY,
bio TEXT,
avatar_url VARCHAR(500),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE user_settings (
user_id BIGINT PRIMARY KEY,
theme VARCHAR(20) DEFAULT 'light',
notifications_enabled BOOLEAN DEFAULT true,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Create indexes
CREATE INDEX idx_profiles_avatar ON user_profiles(avatar_url);
CREATE INDEX idx_settings_theme ON user_settings(theme);
Configuration
Environment Variables
gomigratex supports the following environment variables:
| Variable | Description | Default |
|---|---|---|
DB_DSN |
MySQL connection string | - |
MIGRATIONS_DIR |
Path to migrations directory | ./migrations |
MIGRATIONS_TABLE |
Tracking table name | schema_migrations |
LOCK_TIMEOUT_SEC |
Advisory lock timeout | 30 |
APPLIED_BY |
Identifier for who applied migration | Current user |
DSN Format
The MySQL DSN (Data Source Name) must include specific parameters:
username:password@tcp(host:port)/database?parseTime=true&multiStatements=true
Required parameters:
parseTime=true- Enable automatic time.Time parsingmultiStatements=true- Allow multiple SQL statements per migration
Example:
export DB_DSN="myuser:mypassword@tcp(localhost:3306)/mydb?parseTime=true&multiStatements=true"
With connection pooling:
user:password@tcp(host:port)/db?parseTime=true&multiStatements=true&maxAllowedPacket=67108864&maxOpenConns=25&maxIdleConns=5&connMaxLifetime=300s
Configuration File
Create migratex.yaml for complex configurations:
# Database connection
dsn: "user:password@tcp(localhost:3306)/mydb?parseTime=true&multiStatements=true"
# Migration settings
dir: "./db/migrations"
table: "schema_migrations"
lock_timeout_sec: 60
# Execution settings
applied_by: "ci-deployment"
verbose: true
json: true
dry_run: false
Usage:
migratex up --config migratex.yaml
Advanced Topics
Database Schema
gomigratex creates a tracking table to manage migration state:
CREATE TABLE schema_migrations (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
version VARCHAR(64) NOT NULL,
name VARCHAR(255) NOT NULL,
checksum CHAR(64) NOT NULL,
applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
applied_by VARCHAR(255) NOT NULL,
duration_ms BIGINT NOT NULL,
status ENUM('success','failed') NOT NULL,
execution_order BIGINT NOT NULL,
UNIQUE KEY uniq_version_name (version, name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Fields:
version- Migration timestampname- Migration descriptionchecksum- SHA-256 hash of migration fileapplied_at- When migration was executedapplied_by- Who/what applied the migrationduration_ms- Execution time in millisecondsstatus- Success or failure statusexecution_order- Order of execution
Checksum Validation
gomigratex uses SHA-256 checksums to detect changes to applied migrations:
- When a migration is applied, its checksum is stored
- On subsequent runs, file checksums are compared with stored values
- Mismatches indicate drift and trigger errors
Handling drift:
# After intentionally editing an applied migration
migratex repair --dsn "$DB_DSN" --dir ./migrations
Warning: Only use repair when you understand the implications. Changing applied migrations can lead to inconsistent database states across environments.
Advisory Locking
gomigratex uses MySQL's GET_LOCK() function to prevent concurrent migrations:
SELECT GET_LOCK('gomigratex_lock', 30)
Benefits:
- Prevents race conditions in multi-instance deployments
- Ensures only one migration runs at a time
- Automatically releases locks on connection close
Timeout handling:
# Increase lock timeout for slow migrations
migratex up --dsn "$DB_DSN" --dir ./migrations --lock-timeout 120
Baseline Migrations
For existing databases, use baseline to mark migrations as applied without executing them:
# Mark all migrations up to and including version 20250109120500 as applied
migratex force 20250109120500 --dsn "$DB_DSN" --dir ./migrations
Use cases:
- Importing existing production database
- Starting migrations on legacy systems
- Synchronizing new environments with production
Dry Run Mode
Preview what migrations would be applied without executing them:
migratex up --dsn "$DB_DSN" --dir ./migrations --dry-run
Output:
DRY RUN MODE - No changes will be applied
Pending migrations:
1. 20250109120000_create_users_table.up.sql
2. 20250109120100_add_user_profiles.up.sql
3. 20250109120200_add_posts_table.up.sql
Total: 3 migrations would be applied
Best Practices
1. Always Write Reversible Migrations
Every up migration should have a corresponding down migration:
-- up.sql
CREATE TABLE posts (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
content TEXT
);
-- down.sql
DROP TABLE IF EXISTS posts;
2. Use Transactions for Data Integrity
Wrap complex migrations in transactions:
-- up.sql
START TRANSACTION;
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
total DECIMAL(10,2) NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE INDEX idx_orders_user_id ON orders(user_id);
INSERT INTO orders (user_id, total)
SELECT id, 0.00 FROM users;
COMMIT;
3. Test Migrations Thoroughly
Always test both forward and rollback migrations:
# Test forward migration
migratex up --dsn "$DB_DSN" --dir ./migrations
# Verify application works correctly
# Test rollback
migratex down 1 --dsn "$DB_DSN" --dir ./migrations
# Test forward again
migratex up --dsn "$DB_DSN" --dir ./migrations
4. Use Descriptive Migration Names
# Good β
migratex create add_user_email_verification
migratex create create_product_inventory_table
migratex create add_index_to_orders_created_at
# Bad β
migratex create migration1
migratex create update_db
migratex create fix
5. Handle Data Migrations Carefully
When modifying columns with existing data:
-- up.sql
-- Step 1: Add new column with default
ALTER TABLE users
ADD COLUMN full_name VARCHAR(255) DEFAULT '';
-- Step 2: Populate data
UPDATE users
SET full_name = CONCAT(first_name, ' ', last_name)
WHERE full_name = '';
-- Step 3: Make NOT NULL if needed
ALTER TABLE users
MODIFY COLUMN full_name VARCHAR(255) NOT NULL;
-- Step 4: Drop old columns
ALTER TABLE users
DROP COLUMN first_name,
DROP COLUMN last_name;
6. Keep Migrations Small and Focused
# Instead of one large migration
migratex create massive_database_overhaul
# Create several focused migrations
migratex create add_users_table
migratex create add_posts_table
migratex create add_comments_table
migratex create add_foreign_keys
migratex create add_indexes
7. Document Complex Migrations
-- 20250109120000_optimize_user_queries.up.sql
-- This migration improves user query performance by:
-- 1. Adding composite index on (email, created_at)
-- 2. Converting user_sessions table to InnoDB
-- 3. Partitioning by created_at month
--
-- Expected downtime: ~5 seconds on 1M row table
-- Performance improvement: 3x faster user lookups
-- Rollback safety: Safe, indexes can be dropped without data loss
CREATE INDEX idx_user_email_created ON users(email, created_at);
ALTER TABLE user_sessions ENGINE=InnoDB;
8. Use Consistent Charset and Collation
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
9. Handle Migration Failures Gracefully
Design migrations to be rerunnable or easily fixable:
-- Use IF NOT EXISTS where possible
CREATE TABLE IF NOT EXISTS users (
id BIGINT PRIMARY KEY AUTO_INCREMENT
);
-- Use DROP IF EXISTS for cleanup
DROP TABLE IF EXISTS temp_migration_data;
10. Version Control Everything
# Add migrations to git
git add migrations/
git commit -m "Add user authentication migrations"
# Never manually edit applied migrations
# Instead, create a new migration to fix issues
Troubleshooting
Common Issues and Solutions
1. migratex Command Not Found After Installation
Error:
$ migratex -v
zsh: command not found: migratex
Cause: The Go binary was installed but the Go bin directory is not in your PATH environment variable.
Diagnosis:
# Check if Go is properly installed
go version
# Check Go environment
go env GOPATH
go env GOBIN
# Check if binary was installed
ls -la $(go env GOPATH)/bin/ | grep migratex
# Check if Go bin is in PATH
echo $PATH | tr ':' '\n' | grep go
Solutions:
Option A: Add Go bin to PATH (Recommended)
Add this line to your shell profile (~/.zshrc for zsh or ~/.bash_profile for bash):
export PATH=$PATH:$(go env GOPATH)/bin
Then reload your shell:
source ~/.zshrc # for zsh
# or
source ~/.bash_profile # for bash
Option B: Install with explicit GOBIN
export GOBIN=/usr/local/bin
go install github.com/mirajehossain/gomigratex/cmd/migratex@latest
Option C: Use full path temporarily
$(go env GOPATH)/bin/migratex -v
Verification:
which migratex
migratex -v
# Should output: gomigratex v1.0.x
2. multiStatements=true Required
Error:
Error: You have an error in your SQL syntax
Solution:
Add multiStatements=true to your DSN:
export DB_DSN="user:pass@tcp(localhost:3306)/db?parseTime=true&multiStatements=true"
3. Checksum Drift Detected
Error:
Error: checksum drift detected for migration 20250109120000:create_users_table
Expected: a1b2c3d4...
Got: e5f6g7h8...
Solution: If the file was intentionally modified:
migratex repair --dsn "$DB_DSN" --dir ./migrations
If not intentional, restore the original file from version control.
4. Advisory Lock Timeout
Error:
Error: failed to acquire advisory lock after 30 seconds
Causes:
- Another migration process is running
- Previous migration didn't release lock (crashed)
- Network issues
Solutions:
# Check for other migration processes
ps aux | grep migratex
# Increase timeout
migratex up --dsn "$DB_DSN" --dir ./migrations --lock-timeout 120
# Manually release lock in MySQL
mysql> SELECT RELEASE_LOCK('gomigratex_lock');
5. Migration File Not Found
Error:
Error: migration file not found: 20250109120000_create_users_table.down.sql
Solution:
Ensure both .up.sql and .down.sql files exist for each migration:
ls -la migrations/
6. Connection Issues
Error:
Error: failed to connect to database: dial tcp: lookup localhost: no such host
Solutions:
# Verify DSN format
echo $DB_DSN
# Test connection manually
mysql -h localhost -u user -p database
# Check network connectivity
ping localhost
# Try IP address instead of hostname
export DB_DSN="user:pass@tcp(127.0.0.1:3306)/db?parseTime=true&multiStatements=true"
7. Permission Denied
Error:
Error: CREATE TABLE command denied to user 'app'@'localhost'
Solution: Grant necessary permissions:
GRANT CREATE, ALTER, DROP, INDEX ON database.* TO 'app'@'localhost';
FLUSH PRIVILEGES;
8. Incorrect Migration Order
Error:
Error: foreign key constraint fails
Solution: Ensure migrations are numbered in the correct order:
# List migrations to check order
ls -la migrations/ | sort
# If needed, rename migrations to fix ordering
mv 20250109120200_add_fk.up.sql 20250109120150_add_fk.up.sql
Debug Mode
Enable verbose logging for detailed information:
migratex up --dsn "$DB_DSN" --dir ./migrations --verbose
Output:
INFO: Acquiring advisory lock...
INFO: Lock acquired successfully
INFO: Scanning directory: ./migrations
INFO: Found 3 migration files
INFO: Planning migrations...
INFO: Executing: 20250109120000_create_users_table.up.sql
INFO: Migration completed in 145ms
INFO: Executing: 20250109120100_add_user_profiles.up.sql
INFO: Migration completed in 89ms
INFO: All migrations applied successfully
INFO: Releasing advisory lock
Getting Help
If you encounter issues not covered here:
- Check existing issues: GitHub Issues
- Search discussions: GitHub Discussions
- Create new issue: Provide:
- Go version (
go version) - gomigratex version (
migratex version) - MySQL version
- Complete error message
- Migration files (if relevant)
- Steps to reproduce
- Go version (
Contributing
We welcome contributions from the community! Whether it's bug reports, feature requests, documentation improvements, or code contributions, we appreciate your help.
How to Contribute
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Write tests for new functionality
- Ensure tests pass (
make test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Setup
# Clone the repository
git clone https://github.com/mirajehossain/gomigratex.git
cd gomigratex
# Install dependencies
go mod download
# Run tests
make test
# Run specific package tests
go test ./internal/migrator -v
# Build the CLI
go build -o migratex ./cmd/migratex
# Run integration tests (requires MySQL)
docker-compose up -d
DB_DSN="root:testpass@tcp(127.0.0.1:3306)/testdb?parseTime=true&multiStatements=true" go test -v ./...
docker-compose down
Project Structure
gomigratex/
βββ cmd/
β βββ migratex/ # CLI entry point
βββ internal/
β βββ checksum/ # SHA-256 checksum utilities
β βββ config/ # Configuration management
β βββ db/ # Database connection & operations
β βββ fsutil/ # File system utilities
β βββ lock/ # Advisory locking mechanism
β βββ logger/ # Logging utilities
β βββ migrator/ # Core migration logic
β βββ migrator.go # Main migration runner
β βββ planner.go # Migration planning
β βββ storage.go # Database storage interface
β βββ model.go # Data models
βββ examples/ # Usage examples
βββ migrations/ # Sample migrations
βββ CONTRIBUTING.md # Contribution guidelines
βββ README.md # This file
βββ LICENSE # MIT License
βββ Makefile # Build and test commands
βββ go.mod # Go module definition
Code Standards
- Follow Effective Go guidelines
- Use
gofmtfor code formatting - Write tests for new functionality (aim for >80% coverage)
- Add godoc comments for exported functions and types
- Keep functions small and focused
- Use meaningful variable and function names
Testing
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run specific test
go test -run TestMigrationPlanner ./internal/migrator
# Run with race detector
go test -race ./...
Pull Request Guidelines
- Keep PRs focused: One feature or bug fix per PR
- Write clear descriptions: Explain what and why, not just how
- Link related issues: Use "Fixes #123" or "Relates to #456"
- Update documentation: If you change behavior, update README
- Add tests: New features need tests
- Pass CI checks: Ensure all tests and lints pass
Reporting Bugs
When reporting bugs, please include:
- Clear title: Summarize the issue
- Description: What happened vs. what you expected
- Steps to reproduce: Detailed steps
- Environment: OS, Go version, MySQL version, gomigratex version
- Code samples: Minimal reproducible example
- Error messages: Complete error output
Feature Requests
We love new ideas! When requesting features:
- Check existing issues first
- Describe the problem you're trying to solve
- Suggest a solution if you have one in mind
- Provide use cases to help us understand the value
For more details, see CONTRIBUTING.md.
Versioning
gomigratex follows Semantic Versioning:
- Major version (v1.x.x β v2.x.x): Breaking changes
- Minor version (v1.0.x β v1.1.x): New features, backward compatible
- Patch version (v1.0.0 β v1.0.1): Bug fixes, backward compatible
Checking Version
# Multiple ways to check version
migratex -v
migratex --version
migratex version
Output:
gomigratex v1.0.2
Version Compatibility
| Version | Status | Go Version | MySQL Version |
|---|---|---|---|
| v1.x.x | β Stable | 1.22+ | 5.7+, 8.0+ |
| v0.x.x | β οΈ Beta | 1.22+ | 5.7+, 8.0+ |
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built with β€οΈ for the Go community
FAQ
Q: Can I use gomigratex with databases other than MySQL? A: Currently, gomigratex is optimized specifically for MySQL. Support for PostgreSQL and other databases may be added in future versions.
Q: Is it safe to run migrations in production? A: Yes, gomigratex is production-ready with features like advisory locking, checksum validation, and dry-run mode. However, always test migrations in staging first and have backups.
Q: Can multiple instances run migrations simultaneously? A: No, the advisory lock mechanism ensures only one instance can run migrations at a time, preventing race conditions.
Q: How do I handle long-running migrations?
A: Use the --lock-timeout flag to increase the timeout, and consider breaking large migrations into smaller chunks. Monitor your database during execution.
Q: Can I edit an already-applied migration?
A: It's not recommended. If you must, use migratex repair to update checksums. Better practice is to create a new migration to modify previous changes.
Q: How do I migrate an existing production database?
A: Use the force command to baseline your existing schema, then apply new migrations from that point forward.
Q: Does gomigratex support transaction rollback on failure? A: Individual migration files can use transactions. If a migration fails, it won't be marked as applied, allowing you to fix and retry.
Q: Can I use gomigratex in CI/CD pipelines?
A: Absolutely! Use the --json flag for structured output and the --dry-run flag in validation stages.
Star β this repository if you find it useful!
Follow @mirajehossain for updates.
Questions? Open an issue or discussion.