Quando você trabalha em equipe, um dos maiores desafios é manter o banco de dados sincronizado entre os ambientes.
Alterar uma tabela, adicionar uma coluna ou criar uma nova estrutura pode parecer simples — até que alguém esquece de rodar aquele
script SQL manual, e a aplicação quebra.
É aqui que entram as migrations: uma forma elegante e segura de versionar o banco de dados junto com o código.
Neste artigo, você vai aprender o que são migrations, como usá-las em Go com o Goose, e boas práticas para manter seu banco sempre sob controle.
O que são migrations?
De forma simples, migrations são scripts versionados que descrevem mudanças no banco de dados.
Cada migration representa um passo na evolução do schema — e você pode “subir” ou “descer” versões conforme necessário.
Em frameworks como Django (Python) ou Rails (Ruby), migrations são parte do core.
No Go, não existe um padrão oficial, mas há ótimas bibliotecas que cumprem esse papel:
-
golang-migrate/migrate — popular e madura
-
pressly/goose — simples, prática e com suporte a SQL puro
-
GORM AutoMigrate — automatiza com base nas structs do Go
Neste artigo, vamos usar o Goose, por ser leve e fácil de integrar em qualquer projeto Go.
Configurando migrations com Goose
Vamos colocar a mão na massa.
Crie uma pasta para seu projeto e instale o Goose:
go install github.com/pressly/goose/v3/cmd/goose@latest
Estrutura básica do projeto:
├── db/
│ └── migrations/
├── main.go
├── go.mod
Criando a primeira migration
O comando abaixo cria um novo arquivo de migration:
goose create create_users_table sql
Isso vai gerar algo como:
db/migrations/20251029090000_create_users_table.sql
Abra o arquivo e adicione o conteúdo:
-- +goose Up
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
-- +goose Down
DROP TABLE users;
As seções Up e Down definem, respectivamente, o que fazer ao subir e reverter a migration.
Aplicando migrations
Agora é só executar:
goose postgres "user=postgres dbname=test sslmode=disable" up
Isso aplicará todas as migrations pendentes.
Se quiser desfazer a última:
goose postgres "user=postgres dbname=test sslmode=disable" down
E para verificar o status:
goose postgres "user=postgres dbname=test sslmode=disable" status
Rodando migrations automaticamente no código Go
Você também pode aplicar migrations automaticamente ao iniciar sua aplicação:
package main
import (
"database/sql"
"log"
_ "github.com/lib/pq"
"github.com/pressly/goose/v3"
)
func main() {
db, err := sql.Open("postgres", "user=postgres dbname=test
sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
if err := goose.Up(db, "db/migrations"); err != nil {
log.Fatal(err)
}
log.Println("Migrations aplicadas com sucesso!")
}
Agora, sempre que a aplicação iniciar, ela garantirá que o banco está atualizado.
Boas práticas com migrations
-
Nomeie migrations de forma clara
Use nomes descritivos comoadd_index_to_users_email.sql. -
Sempre inclua rollback (
Down)
É vital poder desfazer mudanças em caso de erro. -
Evite alterar migrations antigas
Cada migration deve refletir o estado histórico do banco. -
Automatize no CI/CD
Adicione um passo no pipeline para rodar migrations automaticamente. -
Teste migrations antes de subir em produção
Use um banco de staging para validar. -
Mantenha as migrations versionadas junto com o código
Isso garante reprodutibilidade entre ambientes (dev, staging, prod).
Comparando ferramentas de migrations em Go
Dica: prefira Goose ou Migrate para produção, pois permitem controle total sobre cada alteração.
Gerenciar a evolução do banco de dados é tão importante quanto versionar o código.
Com o Goose, você ganha controle, rastreabilidade e segurança — garantindo que todos os ambientes estejam sempre alinhados.
Próximo passo?
No próximo artigo, vou mostrar como automatizar migrations Go com Docker e CI/CD, integrando esse processo ao pipeline de deploy.