Миграции баз данных в Go (Golang): полное руководство по инструментам

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Миграции баз данных в Go (Golang): как управлять схемой данных

При разработке приложений на Go рано или поздно возникает необходимость изменять структуру базы данных: добавлять новые таблицы, изменять существующие столбцы, создавать индексы. Ручное выполнение SQL-скриптов на разных окружениях (локальная среда разработки, стейджинг, продакшн) приводит к ошибкам и рассинхронизации. Решение — миграции баз данных (database migrations).

В экосистеме Go существует несколько зрелых библиотек для управления миграциями. В этой статье мы подробно разберём три самых популярных инструмента: golang-migrate/migrate, pressly/goose и rubenv/sql-migrate. Вы узнаете, как установить, настроить и использовать каждую из них, а также познакомитесь с лучшими практиками.

Что такое миграции и зачем они нужны?

Миграция — это файл (или набор файлов), который содержит SQL-команды для изменения схемы базы данных. Каждая миграция имеет уникальный идентификатор (обычно временная метка или номер) и два направления: up (применение изменений) и down (откат изменений).

Основные преимущества использования миграций:

  • Версионирование схемы — история изменений хранится в репозитории вместе с кодом.
  • Воспроизводимость — одинаковые изменения на всех окружениях.
  • Откат изменений — возможность быстро вернуться к предыдущей версии схемы.
  • Командная работа — разработчики не перезаписывают изменения друг друга.

1. golang-migrate/migrate

Самая популярная библиотека для миграций в Go. Поддерживает PostgreSQL, MySQL, SQLite, MongoDB и многие другие базы данных.

Установка

go get -u github.com/golang-migrate/migrate/v4
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest

Структура миграций

Создайте папку migrations и добавьте файлы с префиксом в формате {timestamp}_{title}.{direction}.sql:

migrations/
  000001_create_users_table.up.sql
  000001_create_users_table.down.sql
  000002_add_email_column.up.sql
  000002_add_email_column.down.sql

Пример миграции (up)

-- 000001_create_users_table.up.sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);

Пример миграции (down)

-- 000001_create_users_table.down.sql
DROP TABLE IF EXISTS users;

Применение миграций из Go-кода

package main

import (
    "github.com/golang-migrate/migrate/v4"
    _ "github.com/golang-migrate/migrate/v4/database/postgres"
    _ "github.com/golang-migrate/migrate/v4/source/file"
)

func main() {
    m, err := migrate.New(
        "file://migrations",
        "postgres://localhost:5432/mydb?sslmode=disable")
    if err != nil {
        panic(err)
    }
    if err := m.Up(); err != nil && err != migrate.ErrNoChange {
        panic(err)
    }
}

2. pressly/goose

Goose — лёгкий и быстрый инструмент, который также поддерживает написание миграций на Go (не только на SQL). Идеально подходит для проектов, где требуется логика на стороне кода.

Установка

go get github.com/pressly/goose/v3/cmd/goose

Создание миграции

goose create create_users_table sql

Будет создан файл вида 20250101120000_create_users_table.sql. Содержимое:

-- +goose Up
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

-- +goose Down
DROP TABLE IF EXISTS users;

Go-миграции (продвинутый вариант)

Goose позволяет писать миграции на Go с использованием database/sql:

package migrations

import (
    "database/sql"
    "github.com/pressly/goose/v3"
)

func init() {
    goose.AddMigration(Up, Down)
}

func Up(tx *sql.Tx) error {
    _, err := tx.Exec("CREATE TABLE items (id SERIAL PRIMARY KEY, name TEXT)")
    return err
}

func Down(tx *sql.Tx) error {
    _, err := tx.Exec("DROP TABLE IF EXISTS items")
    return err
}

Рекомендаций