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. 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, o banco de dados relacional open source usado no tutorial original de 2026:
- 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.
- A migração 002 adiciona a coluna username. O migrate down remove a coluna.
- 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, 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, 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 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 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 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.
Fork this article
Start a new branch from the same video, shaped your way. You keep the credit; the original keeps the attribution.
A fork in another language is filed as a translation of this article, so the two pages point at each other. You can unlink it later from the editor.
0/240
You are creating
- Format
- For
- Language
- Source
- Your angle
You will be asked to sign in before it is generated.
Buy credits