Drizzle ORM
Drizzle es un ORM SQL-first para TypeScript: las definiciones de tablas viven en el código, las consultas se sienten como SQL y el tiempo de ejecución se mantiene ligero sobre node-postgres.
Busca en todas las páginas de la documentación
Drizzle es un ORM SQL-first para TypeScript: las definiciones de tablas viven en el código, las consultas se sienten como SQL y el tiempo de ejecución se mantiene ligero sobre node-postgres.
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
// 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;
}Cuándo usarlo:
// 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;
});
}Lo que esto demuestra:
db.transaction envuelve la transacción de Postgresreturning() para resultados de INSERT sin una segunda consultapg se aplica por debajonpx drizzle-kit generate
npx drizzle-kit migratedrizzle/ para revisión de PRimport { 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 } })) está disponible cuando se prefiereimport { 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 etiquetada mantiene la parametrización 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 las consultasonClose.limit(1) en búsquedas únicas - siempre devuelve un array. Solución: limit(1) y toma [0].inArray grandes - paquetes SQL enormes. Solución: agrupa IDs o patrón de tabla temporal.| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Prisma | Studio, ergonomía de relaciones, ecosistema más grande | Quieres un tiempo de ejecución mínimo SQL-first |
| Kysely | Solo constructor de consultas, sin DSL de esquema | Quieres un esquema integrado + kit de migración |
pg + archivos SQL | Los DBA son dueños de todo el SQL | Necesitas inferencia de TS en las columnas |
| TypeORM | Proyectos Nest heredados | Greenfield sin costo de migración |
Drizzle si la transparencia SQL y el peso del tiempo de ejecución importan. Prisma si el DSL del esquema y la velocidad de las herramientas ganan.
Sí, a través de un proveedor personalizado que envuelve la instancia db o módulos Drizzle de la comunidad.
Habilita el logger en drizzle(pool, { logger: true }) solo en desarrollo.
max pequeño en el pool o controlador sin servidor; consulta Ajuste del pool de conexiones.
Sí, cambia el controlador drizzle-orm/better-sqlite3 en el arranque de la prueba.
Soportado en la definición de tabla con la configuración de clave primaria de tupla.
pgEnum en el esquema se mapea al tipo ENUM de Postgres; migra con cuidado en producción.
Usa uniones o consultas relacionales with en un solo viaje de ida y vuelta, la misma disciplina que include de Prisma.
Drizzle es compatible con ESM. Usa "type": "module" y la sintaxis import en todo el proyecto.
Drizzle es típicamente más ligero; compara tus endpoints, no las inserciones de "hola mundo".
pg) - controlador subyacenteVersiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS activa), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.
Revisado por Chris St. John·Última actualización: 16 jul 2026