Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Shrijith Venkatramana
Shrijith Venkatramana

Posted on

     

Best Database Migration Tools for Golang

Hi there! I'm Shrijith Venkatrama, founder of Hexmos. Right now, I’m buildingLiveAPI, a first of its kind tool for helping you automatically index API endpoints across all your repositories. LiveAPI helps you discover, understand and use APIs in large tech infrastructures with ease.

Database migrations are a critical part of building and maintaining Go applications. They keep your database schema in sync with your codebase, handle updates, and ensure your app stays reliable as it evolves. Choosing the right migration tool can save you time, reduce errors, and make deployments smoother. In this post, we’ll dive into thebest database migration tools for Go, with examples, comparisons, and practical insights to help you pick the right one for your project.

I’ve been through the grind of manual migrations and the chaos of mismatched schemas, so I’ll break down each tool’s strengths, quirks, and use cases in a way that’s easy to follow. Let’s explore the top options, complete with code examples you can actually run.

Why Database Migrations Matter in Go

Before we jump into the tools, let’s talk about why migrations are a big deal. In Go projects, your database schema often evolves—new tables, updated columns, or index changes. Without a migration tool, you’re stuck writing raw SQL, manually tracking versions, or praying your team doesn’t mess up the production database. A good migration toolautomates schema changes,tracks history, and ensures consistency across environments.

The tools we’ll cover work well with Go’s ecosystem, integrate with popular databases like PostgreSQL and MySQL, and focus on simplicity or flexibility depending on your needs. Let’s dive into the first tool.

1. Goose: Simple and Lightweight Migrations

Goose is a no-fuss, lightweight migration tool for Go. It’s perfect for developers who wantminimal setup andSQL-based migrations without heavy dependencies. Goose supports PostgreSQL, MySQL, SQLite, and more, and it’s easy to integrate into a Go project.

Key Features

  • SQL or Go-based migrations: Write migrations in raw SQL or Go code.
  • CLI-driven: Run migrations with simple commands likegoose up orgoose down.
  • No external dependencies: Just a Go binary and your database driver.

Example: Creating a User Table with Goose

Here’s how you can set up a migration to create ausers table in PostgreSQL.

First, install Goose:

go get-u github.com/pressly/goose/v3
Enter fullscreen modeExit fullscreen mode

Create a migration file (e.g.,20250607101700_create_users_table.sql):

-- +goose UpCREATETABLEusers(idSERIALPRIMARYKEY,usernameVARCHAR(50)NOTNULL,emailVARCHAR(100)NOTNULLUNIQUE,created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP);-- +goose DownDROPTABLEusers;
Enter fullscreen modeExit fullscreen mode

Run the migration:

goose-dir migrations postgres"user=postgres password=secret dbname=mydb sslmode=disable" up
Enter fullscreen modeExit fullscreen mode

Output: Theusers table is created in your PostgreSQL database. Runninggoose down will drop it.

When to Use Goose

Goose shines for small to medium projects where you wantfull control over SQL and a lightweight tool. It’s not ideal for complex migrations requiring programmatic logic, as its Go-based migrations can feel clunky compared to other tools.

2. Migrate: The CLI Powerhouse

Migrate is another popular choice for Go developers. It’s a CLI-first tool that supports a wide range of databases (PostgreSQL, MySQL, SQLite, etc.) and focuses onsimplicity and portability. Unlike Goose, Migrate is language-agnostic, so it’s great for teams using multiple languages alongside Go.

Key Features

  • Broad database support: Works with almost any database, including cloud-native ones like CockroachDB.
  • File-based migrations: Uses plain SQL files with up/down scripts.
  • CLI focus: No Go code required, making it easy to use in CI/CD pipelines.

Example: Adding a Posts Table with Migrate

Install Migrate:

go get-u github.com/golang-migrate/migrate/v4
Enter fullscreen modeExit fullscreen mode

Create a migration file (e.g.,20250607101800_create_posts_table.sql):

-- +upCREATETABLEposts(idSERIALPRIMARYKEY,user_idINTEGERREFERENCESusers(id),titleVARCHAR(255)NOTNULL,contentTEXT,created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP);-- +downDROPTABLEposts;
Enter fullscreen modeExit fullscreen mode

Run the migration:

migrate-path migrations-database"postgres://postgres:secret@localhost:5432/mydb?sslmode=disable" up
Enter fullscreen modeExit fullscreen mode

Output: Theposts table is created, linked to theusers table viauser_id. Runningmigrate down reverses it.

When to Use Migrate

Migrate is ideal for teams needing alanguage-agnostic tool or working with diverse databases. It’s slightly more complex to set up than Goose but excels inCI/CD integration and cross-database compatibility.

3. Gormigrate: GORM-Friendly Migrations

Gormigrate is a migration library built specifically forGORM, a popular ORM for Go. If your project already uses GORM for database operations, Gormigrate is a natural fit, letting you define migrations in Go code alongside your models.

Key Features

  • GORM integration: Leverages GORM’s ORM capabilities for migrations.
  • Programmatic migrations: Write migrations in Go, not SQL.
  • Rollback support: Easily undo migrations with built-in rollback functions.

Example: Migrating a Products Table with Gormigrate

Here’s a complete example of creating aproducts table using Gormigrate.

packagemainimport("log""gorm.io/driver/postgres""gorm.io/gorm""github.com/go-gormigrate/gormigrate/v2")typeProductstruct{IDuint`gorm:"primaryKey"`Namestring`gorm:"type:varchar(100);not null"`Pricefloat64CreatedAttime.Time}funcmain(){dsn:="host=localhost user=postgres password=secret dbname=mydb port=5432 sslmode=disable"db,err:=gorm.Open(postgres.Open(dsn),&gorm.Config{})iferr!=nil{log.Fatal(err)}m:=gormigrate.New(db,gormigrate.DefaultOptions,[]*gormigrate.Migration{{ID:"20250607101900",Migrate:func(tx*gorm.DB)error{returntx.AutoMigrate(&Product{})},Rollback:func(tx*gorm.DB)error{returntx.Migrator().DropTable("products")},},})iferr:=m.Migrate();err!=nil{log.Fatalf("Could not migrate: %v",err)}log.Println("Migration completed")}// Output: Migration completed
Enter fullscreen modeExit fullscreen mode

Output: Theproducts table is created with columns forid,name,price, andcreated_at. Runningm.Rollback() drops the table.

When to Use Gormigrate

Use Gormigrate if your project isheavily invested in GORM and you prefer defining migrations in Go. It’s less flexible for raw SQL lovers and not ideal for non-GORM projects.

4. SQLx with Custom Migrations: Roll Your Own

SQLx isn’t a migration tool per se, but it’s a powerful library for working with SQL in Go. You can build acustom migration system using SQLx to execute migration scripts, giving you ultimate flexibility. This approach is best for teams who wantfull control over their migration logic.

Key Features

  • SQLx flexibility: Combine SQLx’s query execution with your own migration tracking.
  • Customizable: Build exactly the migration workflow you need.
  • No external CLI: Everything runs in your Go code.

Example: Custom Migration with SQLx

Here’s a simple migration system using SQLx to create anorders table.

packagemainimport("log""github.com/jmoiron/sqlx"_"github.com/lib/pq")typeMigrationstruct{IDstringUpQuerystring}funcmain(){db,err:=sqlx.Connect("postgres","user=postgres password=secret dbname=mydb sslmode=disable")iferr!=nil{log.Fatal(err)}// Create migrations table if it doesn't exist_,err=db.Exec(`CREATE TABLE IF NOT EXISTS migrations (id VARCHAR(50) PRIMARY KEY)`)iferr!=nil{log.Fatal(err)}migrations:=[]Migration{{ID:"20250607102000_create_orders",UpQuery:`                CREATE TABLE orders (                    id SERIAL PRIMARY KEY,                    user_id INTEGER REFERENCES users(id),                    total DECIMAL(10,2),                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP                )`,},}for_,m:=rangemigrations{varexistsboolerr:=db.Get(&exists,"SELECT EXISTS (SELECT 1 FROM migrations WHERE id = $1)",m.ID)iferr!=nil{log.Fatal(err)}if!exists{_,err:=db.Exec(m.UpQuery)iferr!=nil{log.Fatal(err)}_,err=db.Exec("INSERT INTO migrations (id) VALUES ($1)",m.ID)iferr!=nil{log.Fatal(err)}log.Printf("Applied migration: %s",m.ID)}}}// Output: Applied migration: 20250607102000_create_orders
Enter fullscreen modeExit fullscreen mode

Output: Theorders table is created, and the migration is tracked in amigrations table.

When to Use SQLx

Choose SQLx forcustom migration workflows when existing tools don’t fit your needs. It requires more setup but offers unmatched flexibility.

5. Flyway (via Go Integration): Enterprise-Grade Migrations

Flyway is a Java-based migration tool that’s widely used in enterprise settings. While not Go-native, you can integrate it into Go projects using its CLI or by calling its Java library. Flyway is great for teams needingrobust versioning andaudit-ready migration history.

Key Features

  • Versioned migrations: Strict versioning ensures predictable schema changes.
  • Enterprise-friendly: Supports complex workflows and multiple environments.
  • SQL-based: Write migrations in plain SQL.

Example: Running Flyway with Go

Here’s how you can use Flyway’s CLI in a Go project to create acategories table.

First, download Flyway and set up amigrations folder with a file namedV1__create_categories_table.sql:

CREATETABLEcategories(idSERIALPRIMARYKEY,nameVARCHAR(100)NOTNULL,created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP);
Enter fullscreen modeExit fullscreen mode

Run Flyway via a Go program:

packagemainimport("log""os/exec")funcmain(){cmd:=exec.Command("flyway","-url=jdbc:postgresql://localhost:5432/mydb","-user=postgres","-password=secret","migrate")output,err:=cmd.CombinedOutput()iferr!=nil{log.Fatalf("Flyway failed: %v\n%s",err,output)}log.Println("Flyway migration completed")log.Println(string(output))}// Output: Flyway migration completed// (Flyway CLI output follows)
Enter fullscreen modeExit fullscreen mode

Output: Thecategories table is created, and Flyway tracks the migration in itsflyway_schema_history table.

When to Use Flyway

Flyway is ideal forenterprise projects or teams already using it in polyglot environments. It’s overkill for small projects due to its Java dependency and setup complexity.

6. Comparing the Tools: Which One Fits Your Project?

To help you choose, here’s a comparison of the tools based on key criteria.

ToolDatabase SupportMigration TypeEase of UseBest For
GoosePostgreSQL, MySQL, SQLite, etc.SQL, GoHighSmall to medium projects
MigrateAlmost all databasesSQLMediumCI/CD pipelines, diverse DBs
GormigrateGORM-supported DBsGoHighGORM-based projects
SQLx (Custom)Any SQLx-supported DBSQL, GoLowCustom workflows
FlywayMany (via JDBC)SQLMediumEnterprise, multi-language teams

Key takeaway: If you’re unsure, start withGoose for simplicity orMigrate for flexibility. Use Gormigrate for GORM projects, SQLx for custom needs, or Flyway for enterprise-grade requirements.

7. Tips for Smooth Migrations in Go

To wrap up, here are practical tips to make your migrations successful:

  • Version your migrations: Use timestamps or sequential IDs to avoid conflicts (e.g.,20250607102100).
  • Test migrations locally: Always run migrations in a local or staging environment before production.
  • Backup your database: Before applying migrations, ensure you have a backup to avoid data loss.
  • Use transactions: For complex migrations, wrap changes in transactions to ensure atomicity.
  • Document changes: Add comments in migration files to explain the purpose of each change.

Example: Transactional Migration with Goose

Here’s a Goose migration using a transaction for safety:

-- +goose UpBEGIN;CREATETABLEpayments(idSERIALPRIMARYKEY,user_idINTEGERREFERENCESusers(id),amountDECIMAL(10,2),created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP);INSERTINTOpayments(user_id,amount)VALUES(1,99.99);COMMIT;-- +goose DownDROPTABLEpayments;
Enter fullscreen modeExit fullscreen mode

Output: Thepayments table is created, and a sample row is inserted atomically. If anything fails, the transaction rolls back.

What’s Next for Your Go Migrations?

Choosing the right migration tool depends on your project’s size, team, and database needs.Goose andMigrate are great for most Go developers due to their simplicity and SQL focus.Gormigrate is a no-brainer for GORM users, whileSQLx offers flexibility for custom setups.Flyway suits enterprise teams needing robust versioning.

Start by experimenting with one tool in a small project. Run the examples above, tweak them for your database, and see what fits your workflow. Whichever tool you pick, prioritizeautomation,testing, andbackup strategies to keep your migrations smooth and your app reliable.

Top comments(2)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
abdul_basith_db7ce5363bd5 profile image
Abdul Basith
  • Joined

Is any rollback mechanism?

CollapseExpand
 
shrsv profile image
Shrijith Venkatramana
Founder @ hexmos.com
  • Education
    UCI
  • Work
    hexmos.com
  • Joined

Yes. Gomigrate for example asks for both up/down SQL queries to create a migration.

Some comments may only be visible to logged-in visitors.Sign in to view all comments.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Founder @ hexmos.com
  • Education
    UCI
  • Work
    hexmos.com
  • Joined

More fromShrijith Venkatramana

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp