Type-Safe Queries Without Hand-Writing SQL
ORMs — Drizzle & Prisma
ORMs map your database to TypeScript types. Drizzle and Prisma are the two front-runners.
What you'll learn
- Set up Drizzle or Prisma
- Query type-safely
- Decide between them
An ORM (“Object-Relational Mapper”) lets you query your DB using JS/TS objects instead of writing raw SQL. The two most popular choices for Node in 2026: Drizzle and Prisma.
Drizzle — SQL With Types
You write something that looks like SQL; you get typed results.
import { drizzle } from "drizzle-orm/node-postgres";
import { pgTable, serial, text } from "drizzle-orm/pg-core";
import { eq } from "drizzle-orm";
import { Pool } from "pg";
const users = pgTable("users", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
});
const db = drizzle(new Pool({ connectionString: process.env.DATABASE_URL }));
// query
const result = await db.select().from(users).where(eq(users.id, 42));
// insert
await db.insert(users).values({ name: "Ada", email: "ada@example.com" }); - Schema lives in code (no codegen step at query time)
- Generated TS types everywhere
- Closer to SQL — easier to drop into raw when needed
drizzle-kithandles migrations
Prisma — Schema-First, Generated Client
Schema lives in a .prisma file; codegen produces a typed client.
// schema.prisma
model User {
id Int @id @default(autoincrement())
name String
email String @unique
} npx prisma migrate dev
npx prisma generate import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const user = await prisma.user.findUnique({ where: { id: 42 } });
await prisma.user.create({
data: { name: "Ada", email: "ada@example.com" },
}); - Schema lives in DSL (one source of truth)
- Generated client — IntelliSense everywhere
- Excellent migrations + Studio (UI)
- Heavier — adds ~100MB to your build
Choose
| You want | Pick |
|---|---|
| Close to SQL, light runtime | Drizzle |
| Schema-first, more abstractions | Prisma |
| Edge runtimes (Cloudflare Workers) | Drizzle (Prisma support exists but is heavier) |
| Already know SQL well | Drizzle |
| Coming from another ORM background | Prisma |
Both are great. Many large Node apps run either successfully.
The Raw-SQL Escape Hatch
Both let you drop to raw SQL when needed:
// Drizzle
import { sql } from "drizzle-orm";
const rows = await db.execute(sql`SELECT * FROM users WHERE id = ${42}`);
// Prisma
const rows = await prisma.$queryRaw`SELECT * FROM users WHERE id = ${42}`; Use this for complex CTEs, vendor-specific features, or performance optimization.
Redis →