Migrations parecem triviais até a primeira vez que uma altera uma tabela grande em produção e trava o sistema por minutos. Versionar banco de dados exige o mesmo cuidado que versionar código — só que erro de migration custa muito mais caro que erro de código.
A regra que nunca quebro
Toda migration precisa ser reversível, e toda alteração em tabela com muitas linhas em produção precisa ser pensada em termos de lock — algumas operações de ALTER TABLE travam a tabela inteira durante a execução. Antes de rodar qualquer migration em produção, penso primeiro no que acontece se ela travar no meio, e não só no resultado final esperado.
Adicionar coluna não é sempre inofensivo
Adicionar uma coluna NOT NULL sem valor padrão em uma tabela com milhões de linhas pode travar o banco por bastante tempo. Prefiro adicionar como nullable primeiro, popular o valor via Job em lote — a mesma disciplina de processamento assíncrono que descrevo em Jobs e Queues — e só depois de tudo populado, tornar a coluna obrigatória em uma segunda migration.
Onde a interceptação de requisição entra
Depois de garantir que o dado no banco está seguro, o próximo ponto de controle é decidir onde intercepto uma requisição antes dela chegar no Controller — o que discuto em Middleware.



