DEV Community

Alex Spinov
Alex Spinov

Posted on

Drizzle ORM Has a Free API That Makes SQL Type-Safe in TypeScript

Drizzle ORM is the TypeScript ORM that gives you SQL-like syntax with full type safety. No magic, no heavy runtime — just SQL that TypeScript understands.

What Is Drizzle ORM?

Drizzle is a lightweight TypeScript ORM that feels like writing SQL. Unlike Prisma (which generates a heavy client), Drizzle maps directly to SQL with zero overhead.

Getting Started

npm install drizzle-orm pg
npm install -D drizzle-kit @types/pg
Enter fullscreen mode Exit fullscreen mode

Define Your Schema

// schema.ts
import { pgTable, serial, text, integer, timestamp, boolean } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  age: integer('age'),
  active: boolean('active').default(true),
  createdAt: timestamp('created_at').defaultNow(),
})

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content'),
  authorId: integer('author_id').references(() => users.id),
  publishedAt: timestamp('published_at'),
})
Enter fullscreen mode Exit fullscreen mode

Queries (SQL-like, type-safe)

import { drizzle } from 'drizzle-orm/node-postgres'
import { eq, gt, like, desc, count } from 'drizzle-orm'
import { users, posts } from './schema'
import { Pool } from 'pg'

const pool = new Pool({ connectionString: process.env.DATABASE_URL })
const db = drizzle(pool)

// Select with filters
const activeUsers = await db.select()
  .from(users)
  .where(eq(users.active, true))
  .orderBy(desc(users.createdAt))
  .limit(10)

// Join
const postsWithAuthors = await db.select({
  postTitle: posts.title,
  authorName: users.name,
  publishedAt: posts.publishedAt,
})
  .from(posts)
  .leftJoin(users, eq(posts.authorId, users.id))
  .where(gt(posts.publishedAt, new Date('2026-01-01')))

// Aggregate
const postCounts = await db.select({
  author: users.name,
  totalPosts: count(posts.id),
})
  .from(users)
  .leftJoin(posts, eq(users.id, posts.authorId))
  .groupBy(users.name)

// Insert
const newUser = await db.insert(users).values({
  name: 'Alice',
  email: 'alice@example.com',
  age: 28,
}).returning()

// Update
await db.update(users)
  .set({ active: false })
  .where(eq(users.id, 5))

// Delete
await db.delete(posts)
  .where(eq(posts.authorId, 5))
Enter fullscreen mode Exit fullscreen mode

Migrations

# Generate migration
npx drizzle-kit generate

# Apply migration
npx drizzle-kit migrate

# Studio (visual editor)
npx drizzle-kit studio
Enter fullscreen mode Exit fullscreen mode

Drizzle vs Prisma

Feature Drizzle Prisma
Bundle size ~7KB ~2MB
SQL-like syntax Yes No
Type safety Full Full
Raw SQL Built-in Limited
Edge runtime Yes Limited
Learning curve Know SQL? Done New syntax
Migrations SQL files Custom format

Works Everywhere

  • Node.js, Bun, Deno
  • Vercel Edge, Cloudflare Workers
  • PostgreSQL, MySQL, SQLite, Turso
  • Neon, Supabase, PlanetScale

Need to store scraped data efficiently? Scrapfly extracts web data at scale. Email spinov001@gmail.com for database + scraping integrations.

Top comments (0)