Migrações de Banco de Dados com PostgreSQL: Prisma Migrate vs Drizzle Kit
O problema que migração resolve (e o que ela cria)
Alterar a estrutura de um banco PostgreSQL em produção sem um sistema de migrações é como editar código direto no servidor: funciona até o dia que não funciona. Migrações versionam o schema do banco da mesma forma que Git versiona o código. Cada alteração vira um arquivo rastreável, reversível e aplicável em qualquer ambiente.
A questão prática é: qual ferramenta usar? Prisma Migrate e Drizzle Kit resolvem o mesmo problema com filosofias opostas. Prisma gera SQL a partir de um schema declarativo próprio. Drizzle gera SQL a partir de definições TypeScript que espelham a estrutura real do banco. A escolha entre eles afeta como você escreve queries, como faz deploy e como lida com migrações que dão errado.
Se você já trabalha com Prisma no Fastify, este post vai expandir o que você sabe sobre o lado de migrações. Se está avaliando Drizzle, vai sair daqui com critérios concretos para decidir.
Setup: do zero à primeira migração
Prisma Migrate
# Instala Prisma como dependência de desenvolvimento
npm install prisma --save-dev
npm install @prisma/client
# Inicializa o diretório prisma/ com schema.prisma e .env
npx prisma init --datasource-provider postgresql
O arquivo schema.prisma é o ponto central. Toda alteração de schema passa por ele:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// @map renomeia a coluna no banco sem mudar o nome no TypeScript
@@map("users")
}
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
content String? @db.Text
published Boolean @default(false)
authorId Int @map("author_id")
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
@@index([authorId])
@@map("posts")
}
# Gera o SQL de migração e aplica no banco de desenvolvimento
npx prisma migrate dev --name create_users_and_posts
Esse comando faz três coisas: gera um arquivo SQL em prisma/migrations/, aplica no banco e regenera o Prisma Client.
Drizzle Kit
npm install drizzle-orm pg
npm install drizzle-kit --save-dev
npm install @types/pg --save-dev
No Drizzle, o schema é TypeScript puro:
// src/db/schema.ts
import { pgTable, serial, varchar, text, boolean, integer, timestamp } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
email: varchar("email", { length: 255 }).notNull().unique(),
name: varchar("name", { length: 255 }),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: varchar("title", { length: 255 }).notNull(),
content: text("content"),
published: boolean("published").default(false).notNull(),
// Referência explícita à tabela users
authorId: integer("author_id").notNull().references(() => users.id),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
// Relations são separadas da definição de tabela
// Isso mantém o schema da tabela puro e as queries relacionais opcionais
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
// drizzle.config.ts
import { defineConfig } from "drizzl
---
Leia o artigo completo em [https://www.vivodecodigo.com.br/backend/migracoes-postgresql-prisma-migrate-drizzle-kit-guia-pratico-1787140907023](https://www.vivodecodigo.com.br/backend/migracoes-postgresql-prisma-migrate-drizzle-kit-guia-pratico-1787140907023)