golang-migrate: почему стоит остановиться именно на нем?
Если вам нужен инструмент миграций, который:
- работает абсолютно одинаково в Go, Python, Node.js, Rust, CI/CD-скриптах
- поддерживает почти все популярные БД (PostgreSQL, MySQL, SQLite)
- максимально предсказуем и прозрачен
- легко встраивается в любые пайплайны деплоя
то golang-migrate - это по-сути лучший выбор.
Почему он так хорош?
Коротко - это SQL-файлы со скриптами. Нет никакой магии, нет сюрпризов и упрощения. Но и нет подводных камней, которые часто скрывают библиотеки
Как это работает?
- Одна миграция - одно логическое изменение
- Всегда создаете файлы .up.sql и .down.sql (даже если не откатываете таблицу)
- Делайте миграции идемпотентными где возможно: IF NOT EXISTS, CREATE OR REPLACE
- Не храните данные в миграциях (кроме случаев, когда они должны быть заполнены статично)
- Называйте файлы последовательно и описательно
20260130123456_users.up.sql - Тестируйте up → down → up локально перед выкаткой в прод
Пример миграции (Postgres)
-- 20260130123456_create_users.up.sql
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'user',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_users_email ON users USING btree (email);
-- 20260130123456_create_users.down.sql
DROP TABLE IF EXISTS users CASCADE;UPDATE users SET email = old_email;
ALTER TABLE users
ALTER COLUMN email SET NOT NULL,
ADD CONSTRAINT users_email_unique UNIQUE (email);(В down-миграции — обратный процесс)
Как интегрировать в проект
Можно через Makefile / CI
migrate:
migrate -path ./migrations -database "${DATABASE_URL}" up
Это будет самы лучший вариант, в ci/cd можно добавить вызов этой этого скрипта перед сборкой приложения
В каких случаях точно стоит использовать
- Микросервисы на разных языках
- Строгий GitOps / CI/CD (ArgoCD, GitHub Actions, etc.)
- Нужно поддерживать много разных БД в компании
- Важна максимальная предсказуемость и минимум магии
Личный опыт
На мой взгляд это самый лучший вариант миграций, он более "долгий" в процессе разработки новых реп, но в конечном итоге - более предсказуемый, а также более ультимативный. Вы можете добавить туда любой sql без костылей, что упростит вам развитие сервиса в дальнейшем, и я почти уверен, что вам никогда не придется его переписывать на библиотеку и всякие "авто-миграторы" из структур. Что может быть лучше?)
Ну и еще одно преимущество, которое можно упустить.- низкий порог входа. Любой бекенд-разработчик знает sql, и легко напишет такую миграцию. А вот со всякими либами нужно порой разбираться отдельно…