go-migrationgo-migration
Migrations
Documentation

Running Migrations

Learn how to execute pending migrations using the m.Up() method and understand batch tracking.

Running Migrations

Once your migrations are registered, use m.Up() to execute all pending migrations.

The m.Up() Method

go
if err := m.Up(); err != nil {
    log.Fatal(err)
}

m.Up() runs all migrations that haven't been executed yet, in alphabetical order by name.

What Happens During Execution

Migration Table Check

go-migration checks if the migrations tracking table exists. If not, it creates one automatically to record which migrations have run.

Pending Migration Detection

The migrator compares your registered migrations against the tracking table to determine which ones are pending (not yet executed).

Sequential Execution

Each pending migration's Up method is called in order. By default, each migration runs inside its own database transaction.

Batch Recording

All migrations executed in a single m.Up() call are assigned the same batch number. This batch number is used for rollback operations.

Complete Example

main.go
package main

import (
    "database/sql"
    "log"

    _ "github.com/lib/pq"

    "github.com/gopackx/go-migration/migrator"
    "your-project/migrations"
)

func main() {
    db, err := sql.Open("postgres", "postgres://user:password@localhost:5432/mydb?sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    m := migrator.New(db)

    m.Register("20240101_create_users_table", &migrations.CreateUsersTable{})
    m.Register("20240115_create_posts_table", &migrations.CreatePostsTable{})

    // Run all pending migrations
    if err := m.Up(); err != nil {
        log.Fatal(err)
    }

    log.Println("All migrations completed successfully!")
}

Idempotent Behavior

Calling m.Up() multiple times is safe. Migrations that have already run are skipped — only pending migrations are executed. This makes it safe to call m.Up() on every application startup.

If a migration fails partway through, the transaction for that specific migration is rolled back. Previously completed migrations in the same batch remain applied. See Transactions for details.

Progress Reporting

Use the WithProgress option to receive real-time progress events as each migration executes. This is useful for logging, progress bars, or monitoring long-running migration batches.

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"

    "github.com/gopackx/go-migration/migrator"
    "your-project/migrations"
)

func main() {
    db, err := sql.Open("postgres", "postgres://user:password@localhost:5432/mydb?sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    m := migrator.New(db, migrator.WithProgress(func(e migrator.ProgressEvent) {
        fmt.Printf("[%d/%d] %s %s (%s)\n", e.Index, e.Total, e.Direction, e.Name, e.Duration)
    }))

    m.Register("20240101_create_users_table", &migrations.CreateUsersTable{})
    m.Register("20240115_create_posts_table", &migrations.CreatePostsTable{})

    if err := m.Up(); err != nil {
        log.Fatal(err)
    }
}

Example Output

[1/2] up 20240101_create_users_table (12ms)
[2/2] up 20240115_create_posts_table (8ms)

The ProgressEvent struct contains:

FieldTypeDescription
NamestringThe migration name
Indexint1-based index of the current migration
TotalintTotal number of migrations being executed
Durationtime.DurationTime taken for this migration
Directionstring"up" or "down"

Progress events fire for both Up() and Rollback() operations. The Direction field tells you which way the migration ran.

The progress callback is invoked after each migration completes successfully. If a migration fails, no progress event is emitted for it.

What's Next?