Migrations no Prisma 7: dev, status e deploy
Crie, revise e aplique migrations do Prisma 7 no PostgreSQL, trate uma coluna obrigatória com dados existentes e separe migrate dev de migrate deploy.
Migration no Prisma é um arquivo SQL versionado que leva o banco de uma estrutura
conhecida para a próxima. prisma migrate dev cria e aplica mudanças no ambiente
de desenvolvimento; prisma migrate status compara histórico e banco; prisma migrate deploy aplica migrations pendentes em staging ou produção.
Nesta lição, você criará uma tabela, inserirá dados e tentará adicionar uma coluna obrigatória. O Prisma recusará a mudança porque duas linhas já existem. Depois a gente fará uma evolução em etapas, revisará o SQL e aplicará o mesmo histórico num banco limpo.
O ponto de partida é ter concluído a instalação do Prisma 7 com PostgreSQL
e saber como models e atributos formam o schema.
Se NOT NULL, índice e foreign key ainda não estão claros, consulte também o
guia de PostgreSQL enquanto lê o SQL gerado.
Reforma com caderno de obras: o modelo mental
Imagine uma loja que abre todos os dias. A planta desejada mostra uma nova sala, mas a equipe precisa de um caderno de obras: qual parede será alterada, em que ordem e o que acontece com o estoque que já ocupa o espaço. Entregar só a planta final não explica como sair do estado atual sem perda.
No mapa técnico, schema.prisma é o estado desejado, cada migration.sql é uma
etapa da obra, a tabela _prisma_migrations é o registro do que já foi aplicado
e PostgreSQL é a loja em funcionamento. O limite da analogia: migrations podem
incluir transformação de dados e operações que bloqueiam concorrência; revisar o
SQL e planejar rollout continua necessário.
O comportamento essencial é sequencial. Cada ambiente aplica o mesmo histórico na mesma ordem. Editar uma migration antiga depois que outra máquina a executou é como trocar uma página do caderno sem mudar a obra que já aconteceu.
A configuração aponta schema, pasta e conexão
No Prisma 7, a CLI lê as rotas e a URL em prisma.config.ts:
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
},
datasource: {
url: env("DATABASE_URL"),
},
});Use uma base de desenvolvimento que possa ser recriada. migrate dev precisa de
shadow database para reexecutar o histórico e detectar drift. Credenciais com
permissão limitada demais podem impedir essa etapa; não resolva apontando o
comando para produção.
A primeira migration cria um ponto de partida
Comece com Livro:
generator client {
provider = "prisma-client"
output = "../generated/prisma"
moduleFormat = "esm"
}
datasource db {
provider = "postgresql"
}
model Livro {
id Int @id @default(autoincrement())
titulo String
@@map("livros")
}Crie e aplique a migration em desenvolvimento:
npx prisma migrate dev --name inicialThe following migration(s) have been created and applied from new schema changes:
prisma/migrations/ └─ 20260823013543_inicial/ └─ migration.sql
Your database is now in sync with your schema.
Seu timestamp será diferente. O nome inicial ajuda pessoas a reconhecer a
intenção; não precisa descrever cada coluna. A pasta e o SQL entram no Git junto
da alteração do schema.
Leia o SQL antes de aceitar a mudança
O arquivo produzido no teste contém:
CREATE TABLE "livros" (
"id" SERIAL NOT NULL,
"titulo" TEXT NOT NULL,
CONSTRAINT "livros_pkey" PRIMARY KEY ("id")
);Confira NOT NULL, defaults, índices e foreign keys. Em alterações grandes,
procure operações que reescrevem tabela, adquirem lock forte ou falham diante de
dados existentes. Prisma gera o ponto de partida, mas você é responsável por
aprovar o SQL.
O histórico agora tem duas representações no banco: a tabela livros e a linha
registrada em _prisma_migrations. Veja o estado:
npx prisma migrate statusDatabase schema is up to date!
“Up to date” significa que o histórico local e as migrations registradas como
aplicadas concordam. O comando não compara cada tabela com schema.prisma, não
prova que os dados estão corretos e não substitui a detecção de drift feita por
migrate dev no ambiente de desenvolvimento.
Uma coluna obrigatória encontra dados antigos
Depois da primeira migration, o teste inseriu dois livros:
INSERT INTO livros (titulo)
VALUES ('Olhos d''água'), ('Becos da memória');Agora acrescente ISBN obrigatório:
model Livro {
id Int @id @default(autoincrement())
titulo String
isbn String @unique
@@map("livros")
}Ao rodar npx prisma migrate dev --name isbn_obrigatorio, a saída real foi:
• Step 0 Added the required column isbn to the livros table without a default value. There are 2 rows in this table, it is not possible to execute this step.
You can use prisma migrate dev –create-only to create the migration file, and manually modify it to address the underlying issue(s).
O erro protege dados que já existem. PostgreSQL não sabe qual ISBN preencher nas
duas linhas, e NOT NULL proíbe ausência. Inventar um default igual para todas
também violaria unique e seria uma regra falsa.
Evolua em etapas quando a tabela já tem linhas
Uma estratégia segura é adicionar a coluna opcional, publicar código que preenche os registros antigos e só depois torná-la obrigatória. Primeiro:
model Livro {
id Int @id @default(autoincrement())
titulo String
isbn String? @unique
@@map("livros")
}Crie adiciona_isbn, leia o aviso de unicidade e confirme no ambiente de
desenvolvimento. O SQL testado foi:
ALTER TABLE "livros" ADD COLUMN "isbn" TEXT;
CREATE UNIQUE INDEX "livros_isbn_key" ON "livros"("isbn");PostgreSQL permite vários NULLs nesse índice único, então as duas linhas
antigas sobrevivem. Em seguida, execute um backfill que atribui ISBN real a cada
livro. Só numa migration posterior retire o ?, depois de medir que não resta
NULL.
Em tabela grande, criar índice único pode bloquear ou consumir recursos. Uma
migration customizada pode exigir estratégia específica do PostgreSQL. Use
--create-only, ajuste o SQL com revisão e teste numa cópia representativa.
npx prisma migrate dev --name adiciona_isbn --create-only
# revise prisma/migrations/..._adiciona_isbn/migration.sql
npx prisma migrate dev
npx prisma generateO último comando é separado de propósito: Prisma 7 não gera Client
automaticamente depois de migrate dev.
Dev cria; deploy só aplica o histórico
Os comandos pertencem a ambientes diferentes:
| Comando | Ambiente | Comportamento |
|---|---|---|
prisma migrate dev |
desenvolvimento | Detecta mudanças, usa shadow database, cria migration, aplica e pode pedir reset. |
prisma migrate status |
diagnóstico | Compara migrations locais com registros aplicados e informa pendências. |
prisma migrate deploy |
staging/produção | Aplica migrations pendentes; não cria novas, não usa shadow database e não gera Client. |
prisma db push |
protótipo descartável | Sincroniza schema sem histórico de migration para transportar entre ambientes. |
Não execute migrate dev num deploy. Ele é interativo e pode propor reset diante
de drift ou conflito. O pipeline deve receber migrations já criadas e revisadas.
Um banco limpo comprova que o histórico viaja
No teste, um segundo PostgreSQL vazio recebeu as duas migrations com:
npx prisma migrate deployApplying migration 20260823013543_inicial
Applying migration 20260823013634_adiciona_isbn
The following migration(s) have been applied:
migrations/ └─ 20260823013543_inicial/ └─ migration.sql └─ 20260823013634_adiciona_isbn/ └─ migration.sql
All migrations have been successfully applied.
Esse é o teste que importa: não apenas “funciona na minha base”, mas um ambiente vazio chega ao mesmo estado seguindo o histórico. Em projeto profissional, faça isso no CI e também teste upgrade com dados parecidos com os reais.
Drift é diferença entre história e realidade
Se alguém executa ALTER TABLE manualmente sem registrar uma migration, o banco
e o histórico deixam de contar a mesma história. migrate dev reexecuta as
migrations numa shadow database e compara o resultado, podendo pedir reset do
ambiente de desenvolvimento.
Não aceite reset sem saber qual banco está na URL. O comando apaga dados do schema de desenvolvimento para reconstruí-lo. Antes de confirmar, confira host, database e ambiente. Em produção, preserve o estado, investigue a diferença e prepare uma reconciliação explícita.
Uma política útil é proibir alteração manual de estrutura fora de uma migration, exceto hotfix documentado com plano imediato de baseline ou migration equivalente. Também mantenha migrations no mesmo pull request do schema que elas implementam.
Missão: faça uma mudança que não pode ser imediata
Crie uma tabela Cliente com duas linhas e depois acrescente telefone String
obrigatório. Reproduza o bloqueio de migration. Corrija em três passos: torne o
campo opcional, aplique; preencha telefones distintos; retire ? numa segunda
migration.
SELECT COUNT(*) AS sem_telefone
FROM clientes
WHERE telefone IS NULL;Seu critério de sucesso: o primeiro migrate falha sem alterar dados; a primeira
migration contém coluna anulável; a consulta retorna zero depois do backfill; a
segunda adiciona NOT NULL; um banco vazio aplica o histórico inteiro com
migrate deploy.
Finalize rodando prisma migrate status e prisma generate. Depois volte ao
guia de Prisma ORM 7 e confira se você consegue explicar a
diferença entre schema desejado, SQL versionado, estado aplicado e Client gerado.
Perguntas frequentes
Qual a diferença entre migrate dev e migrate deploy?
Prisma 7 gera Client depois de migrate dev?
Posso editar uma migration já aplicada?
Quando usar db push no lugar de migrate dev?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em Node 24.16.0, Prisma ORM 7.9.1, @prisma/adapter-pg 7.9.1, PostgreSQL 18.6 em postgres:18-alpine e Docker 29.5.3, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- Prisma Migrate — visão geral — prisma.io
- Prisma Migrate — getting started — prisma.io
- Prisma CLI — migrate dev — prisma.io
- Prisma — deploy de mudanças do banco — prisma.io


