Drizzle ORM
Drizzle é um ORM SQL-first para TypeScript: definições de tabela vivem no código, queries parecem SQL e o runtime permanece fino sobre node-postgres.
Busque em todas as páginas da documentação
Drizzle é um ORM SQL-first para TypeScript: definições de tabela vivem no código, queries parecem SQL e o runtime permanece fino sobre node-postgres.
Cartão de referência rápida - pronto para copiar e colar.
// src/db/schema.ts
import { pgTable, text, timestamp, integer } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: text("id").primaryKey(),
email: text("email").notNull().unique(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
export const orders = pgTable("orders", {
id: text("id").primaryKey(),
userId: text("user_id").notNull().references(() => users.id),
totalCents: integer("total_cents").notNull(),
});import { drizzle } from "drizzle-orm/node-postgres";
import pg from "pg";
import { eq } from "drizzle-orm";
import { users } from "./schema";
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
export const db = drizzle(pool);
export async function findUserByEmail(email: string) {
const rows = await db.select().from(users).where(eq(users.email, email)).limit(1);
return rows[0] ?? null;
}Quando usar isso:
// src/db/index.ts
import { drizzle } from "drizzle-orm/node-postgres";
import pg from "pg";
import * as schema from "./schema";
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
max: 10,
});
export const db = drizzle(pool, { schema });
// src/repositories/order-repo.ts
import { db } from "../db";
import { orders, orderItems } from "../db/schema";
import { eq } from "drizzle-orm";
export async function createOrder(
userId: string,
items: { sku: string; qty: number; priceCents: number }[]
) {
const totalCents = items.reduce((s, i) => s + i.qty * i.priceCents, 0);
return db.transaction(async (tx) => {
const [order] = await tx
.insert(orders)
.values({ id: crypto.randomUUID(), userId, totalCents })
.returning();
await tx.insert(orderItems).values(
items.map((i) => ({
id: crypto.randomUUID(),
orderId: order.id,
sku: i.sku,
qty: i.qty,
priceCents: i.priceCents,
}))
);
return order;
});
}O que isso demonstra:
db.transaction envolve transação Postgresreturning() para resultados de INSERT sem uma segunda querypg se aplica por baixo dos panosnpx drizzle-kit generate
npx drizzle-kit migratedrizzle/ para revisão de PRmigrate antes do deploy da aplicação, o mesmo que a política da Prismaimport { db } from "./db";
import { users, orders } from "./schema";
import { eq } from "drizzle-orm";
const rows = await db
.select({
userId: users.id,
email: users.email,
orderId: orders.id,
totalCents: orders.totalCents,
})
.from(users)
.innerJoin(orders, eq(orders.userId, users.id))
.where(eq(users.id, userId));db.query.users.findMany({ with: { orders: true } })) disponível quando preferidoimport { sql } from "drizzle-orm";
await db.execute(sql`
SELECT date_trunc('day', created_at) AS day, COUNT(*)::int AS cnt
FROM orders GROUP BY 1
`);sql com template mantém a parametrização para fragmentos dinâmicosimport fp from "fastify-plugin";
import { db } from "./db";
export const dbPlugin = fp(async (fastify) => {
fastify.decorate("db", db);
});fastify.db para queriesonClose.limit(1) em buscas únicas - sempre retorna um array. Correção: limit(1) e pegue [0].migrate no CI - erros de runtime em colunas ausentes. Correção: migrate como portão de deploy.inArray grandes - pacotes SQL enormes. Correção: lote de IDs ou padrão de tabela temporária.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Prisma | Studio, ergonomia de relations, ecossistema maior | Quer runtime mínimo SQL-first |
| Kysely | Apenas query builder, sem DSL de schema | Quer kit integrado de schema + migrate |
pg + arquivos SQL | DBAs controlam todo o SQL | Precisa de inferência TS em colunas |
| TypeORM | Projetos Nest legados | Greenfield sem custo de migração |
Drizzle se transparência SQL e peso de runtime importam. Prisma se DSL de schema e velocidade de tooling vencem.
Sim, via provider customizado que envolve a instância db ou módulos Drizzle da comunidade.
Habilite o logger em drizzle(pool, { logger: true }) apenas em desenvolvimento.
max pequeno no pool ou driver serverless; veja Ajuste de Pool de Conexão.
Sim - troque o driver drizzle-orm/better-sqlite3 no bootstrap de testes.
Suportadas na definição de tabela com configuração tuple primaryKey.
pgEnum no schema mapeia para o tipo ENUM do Postgres - migre com cuidado em produção.
Use joins ou queries relacionais with em uma única viagem - a mesma disciplina que include da Prisma.
Drizzle é amigável a ESM. Use "type": "module" e sintaxe import em todo o código.
Drizzle é tipicamente mais leve; faça benchmark dos seus endpoints, não de inserts "hello-world".
pg) - driver subjacenteVersões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, e NestJS 11.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026