Drizzle ORM
Drizzle ORM: lightweight, SQL-first TypeScript ORM. Type-safe queries, migrations, and zero-cost abstractions.
Node — Drizzle ORM
EXAMPLE
// Install: npm install drizzle-orm
// npm install -D drizzle-kit
// npm install postgres (or mysql2, better-sqlite3)
// ===== Schema =====
// src/db/schema.ts
import { pgTable, serial, text, integer, timestamp, boolean } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: text('email').notNull().unique(),
name: text('name'),
createdAt: timestamp('created_at').defaultNow(),
});
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
authorId: integer('author_id').references(() => users.id),
published: boolean('published').default(false),
});
// ===== Connect =====
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle(client);
// ===== Query =====
import { eq, and, desc } from 'drizzle-orm';
// Insert
const u = await db.insert(users).values({ email: 'a@x.io', name: 'Alex' }).returning();
// Select
const all = await db.select().from(users).where(eq(users.email, 'a@x.io'));
// Join
const result = await db
.select({ id: posts.id, title: posts.title, author: users.name })
.from(posts)
.innerJoin(users, eq(posts.authorId, users.id))
.where(eq(posts.published, true))
.orderBy(desc(posts.id))
.limit(20);
// Update
await db.update(users).set({ name: 'Sam' }).where(eq(users.id, 1));
// Delete
await db.delete(users).where(eq(users.id, 1));
// Transactions
await db.transaction(async (tx) => {
await tx.insert(users).values({ email: 'b@x.io' });
await tx.insert(posts).values({ title: 'Hi', authorId: 1 });
});
// ===== Relational queries =====
// schema:
export const usersRelations = relations(users, ({ many }) => ({ posts: many(posts) }));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));
// query:
const withPosts = await db.query.users.findMany({
with: { posts: true },
});
// ===== Migrations =====
// drizzle.config.ts
import type { Config } from 'drizzle-kit';
export default {
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: { url: process.env.DATABASE_URL! },
} satisfies Config;
// Commands:
// npx drizzle-kit generate create SQL migration files
// npx drizzle-kit migrate apply migrations
// npx drizzle-kit studio visual DB browser
// ===== Patterns =====
// - Schema in code; migrations in source control
// - SQL-first; ORM is thin
// - Relations for typed includes
// - Use studio for ad-hoc exploration
// ===== Pitfalls =====
// - Not generating after schema changes
// - Forgetting .returning() on insert (no PK back)
// - Drizzle is SQL-aware; understand what each query compiles to
Why it matters
Drizzle ORM is the SQL-first, TypeScript-native alternative to Prisma. Schema in code, queries that compile to clean SQL, relational shorthand for typed includes. Lighter than Prisma; great for serverless + edge.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import { drizzle } from 'drizzle-orm/node-postgres';
const db = drizzle(client);
const rows = await db.select().from(users).where(eq(users.active, true));
Try it Yourself »
Discussion
Loading…