# Como Fazer Migrações de Banco de Dados sem Erros?

> Published 2026-10-11T13:57:28.769Z on https://www.crazystack.com.br/pt/p/como-fazer-migracoes-de-banco-de-dados-sem-erros/
> Source video: https://www.youtube.com/watch?v=Go7rKLtJ0ec

Migrações de banco de dados devem viver na codebase, versionadas no Git e sujeitas a pull request, nunca executadas à mão via SSH na cloud. Comandos soltos aplicados direto na produção não são revisáveis, reproduzíveis nem auditáveis, e qualquer rollback vira um jogo de adivinhação. Neste artigo, você vê como fazer isso com scripts SQL puros no PostgreSQL e com a ORM Drizzle, incluindo migrate up, migrate down e versionamento.

## O que é uma migração de banco de dados

Uma migração de banco de dados é uma mudança controlada e versionada no schema, como adicionar uma coluna ou criar uma tabela. Imagine uma tabela users já em produção, com 300 registros contendo id, nome e e-mail. Se você precisa de um campo de data de nascimento, escreve uma migração que executa o ALTER TABLE equivalente — e outra que sabe reverter.

A migração tem dois lados. O migrate up aplica a mudança, adicionando a coluna nascimento. O migrate down desfaz, removendo a coluna que você acabou de criar. Sempre reverta exatamente aquilo que a migração anterior fez.

Cada migração recebe um número, uma versão. O próprio banco guarda internamente qual versão está aplicada. Se você bate o olho e vê que está na versão 003, sabe em que estado o schema está e consegue migrar para cima ou para baixo com previsibilidade.

## Por que executar SQL na mão é a abordagem errada

Executar comandos SQL manualmente direto no servidor é a abordagem errada para migrações de banco de dados. Dar SSH na cloud e rodar ALTER TABLE, criar colunas ou foreign keys na mão gera mudanças que não são revisáveis, auditáveis, reproduzíveis nem automatizáveis.

O problema cresce quando você tem mais de um ambiente. Você aplica o comando na sua máquina, depois precisa repetir em desenvolvimento, em staging e em produção. Se algo der errado e você precisar voltar atrás, perde a informação do que foi executado e de como foi feito.

A recomendação não é só trocar o terminal por um arquivo: é tratar arquivos de migração com a mesma seriedade do código. Isso significa mantê-los dentro da codebase, sujeitos a pull request, review e controle de versão com [Git](https://git-scm.com/). Se o processo é bom para código, é bom para o schema.

## Como funcionam migrate up, migrate down e versionamento

O modelo versionado funciona como uma escada de estados. Cada migração é um degrau com um migrate up e um migrate down, e o banco registra o degrau atual. Você pode pensar nas migrações como operações 1, 2, 3, 4, 5, cuja aplicação em sequência leva o schema a um estado final conhecido.

Um exemplo concreto com três migrações em um [PostgreSQL](https://www.postgresql.org/), o banco de dados relacional open source usado no tutorial original de 2026:

1. A migração 001 cria a tabela users com id e e-mail e insere dois usuários. O migrate down faz um DROP TABLE.
2. A migração 002 adiciona a coluna username. O migrate down remove a coluna.
3. A migração 003 preenche os usernames e cria uma restrição de unicidade. O migrate down derruba a constraint e nulifica os valores.

Um script migrador identifica em qual versão o banco está e aplica tudo o que falta até a versão alvo. É por isso que, após dar rollback três vezes, um novo migrate aplica somente a migração pendente: o script consulta a versão registrada e pula as que já rodaram. Se você fizer isso manualmente, de uma em uma, funciona — mas não há motivo para abrir mão de algo reproduzível.

## Migrações na prática com PostgreSQL e scripts SQL

O cenário de laboratório usa um Postgres 16 (imagem alpine) levantado com [Docker Compose](https://docs.docker.com/compose/), a ferramenta da Docker que orquestra contêineres locais a partir de um arquivo YAML. Com docker compose up, você tem um banco zerado na máquina, com usuário e senha de teste definidos no compose.

Ao lado dos arquivos de migração, ficam scripts simples: um migrate, um rollback e um de query. Rodar a query antes das migrações retorna o erro esperado, a relação users não existe. Depois de rodar o migrate, o script aplica 001, 002 e 003 em sequência, e a query SELECT email FROM users ORDER BY id retorna os dados populados.

| Aspecto | SQL cru com scripts | ORM gerando migrações |
| --- | --- | --- |
| Origem da migração | Escrita à mão em SQL | Derivada do schema no código |
| Rollback | migrate down manual | Gerado junto pelo comando |
| Risco de esquecer algo | Médio, depende do autor | Menor, a ferramenta compara estados |
| Controle fino do SQL | Total | Às vezes exige ajuste manual |
| Curva de aprendizado | SQL e shell | Sintaxe da ORM e do schema |

Você mesmo pode escrever esses scripts, e uma IA de assistência não tem dificuldade em gerá-los. O ponto essencial: teste localmente, rode um migrate up, um rollback, verifique a tabela em cada cenário antes de levar qualquer script para perto da produção.

## Migrações com a ORM Drizzle: do schema ao arquivo gerado

A maioria das empresas não trabalha com migrações cruas no dia a dia, e sim com uma ORM, ferramenta que envolve o banco e permite lidar com o schema direto na linguagem do projeto. Com a [Drizzle ORM](https://orm.drizzle.team/), ORM em TypeScript para bancos SQL, você descreve o schema no próprio código.

No projeto de exemplo, duas dependências aparecem: a drizzle-orm e a drizzle-kit, a ferramenta de linha de comando que gera e aplica migrações. O schema define uma tabela users com um id serial e chave primária, um e-mail texto não nulo e único, e um username texto não nulo e único. Em outras stacks a ideia é a mesma: Java descreve em Java, Ruby on Rails em Ruby, Laravel em PHP.

Rodando npm run generate, a Drizzle transforma o schema em arquivos de migração. Em um banco zerado, ela cria a migração zero, que gera a tabela com todas as restrições. Depois, npm run migrate aplica tudo usando a própria drizzle-kit.

Aqui está a inversão de caminho que diferencia a ORM: você não escreve o SQL, você declara o estado final. Quer um campo decimal novo na tabela users? Adiciona no schema, roda o generate, e a ferramenta compara o estado atual com o desejado usando journals, snapshots e migrations internos para derivar a migração certa. Quer deletar os campos? Edita o schema, gera de novo, e sai uma migração que derruba constraints e colunas.

Isso não dispensa entendimento. Se a ORM gerar algo estranho, você ainda pode ajustar o arquivo de migração manualmente — e a [documentação da drizzle-kit](https://orm.drizzle.team/docs/kit-overview) deixa claro quais comandos existem para gerar, aplicar e inspecionar migrações.

## Cuidados em produção: locks, staging e testes

Gerar a migração automaticamente não garante que ela seja segura. Um caso real citado no vídeo: alterar uma tabela users com cerca de 100.000 registros para adicionar um campo derivado travou a tabela por aproximadamente 5 minutos por causa de um lock. Migrações pesadas continuam difíceis, com ou sem ORM.

Adicionar uma restrição de e-mail único em uma tabela grande pode falhar ou travar dependendo do volume de dados. Você precisa saber o que o banco vai executar e como, e fazer um teste em staging com dados similares aos da produção antes de qualquer deploy.

- Versione as migrações dentro da codebase, sujeitas a pull request e review.
- Execute sempre por scripts reproduzíveis, nunca por comandos soltos no terminal da cloud.
- Teste migrate up e migrate down localmente em todos os cenários antes de aplicar fora do seu ambiente.
- Meça o impacto de migrações pesadas em staging com volume realista de dados.

Se você seguir esse processo, os problemas que surgirem serão muito mais fáceis de diagnosticar: dá para identificar de onde veio a falha e qual migração a causou. Rodando scripts de qualquer jeito no banco, mais cedo ou mais tarde, vai dar ruim.

## FAQ

- **Posso criar arquivos de migração manualmente?** Sim. O que se condena é executar comandos SQL direto nos ambientes sem registro. Arquivos escritos à mão, desde que versionados no Git e aplicados por script reproduzível, fazem parte do processo recomendado.

- **Preciso de uma ORM para fazer migrações de banco de dados?** Não. Scripts SQL puros com um migrador que controla versões funcionam bem, como mostrado com o PostgreSQL. A ORM apenas inverte o fluxo: você declara o estado final do schema e ela deriva os arquivos de migração.

- **O que acontece se eu rodar rollback e depois migrate de novo?** O script consulta a versão registrada no banco. Depois de reverter uma migração, um novo migrate aplica somente a que ficou pendente, pulando as que já estão aplicadas.

- **A migração gerada pela ORM está sempre correta?** Não. Uma migração gerada automaticamente pode travar tabelas grandes, falhar com restrições de unicidade ou demorar muito em produção. Teste em staging com dados similares antes de aplicar.

## Do vídeo ao artigo: transforme esse conhecimento em conteúdo escrito

A lógica deste artigo é a mesma de uma boa migração: partir de um material bruto, um vídeo de 16 minutos, e chegar a um estado final organizado, revisável e consultável. Se você produz conteúdo técnico em vídeo, cursos como o [Crazystack](https://crazystack.com.br) ou o Bootcamp do Dev Doido mostram quanto conhecimento fica preso em aulas gravadas — conteúdo que muita gente buscaria em formato de texto.

O [Skala Blog](https://skalablog.com) faz exatamente essa conversão: você cola a URL de um vídeo do YouTube, a plataforma transcreve e gera um artigo estruturado, pronto para você revisar e publicar. Assim como as migrações preservam o histórico do banco, seu conteúdo de vídeo passa a ter uma versão escrita, indexável e duradoura.

[Source video](https://www.youtube.com/watch?v=Go7rKLtJ0ec)
