Drizzle ORM gives you type-safe SQL queries with a schema defined in TypeScript, a bundle size small enough for edge functions, and performance faster than Prisma for most query patterns. It is not a replacement for Prisma in every case, but for performance-sensitive applications and serverless deployments, it is often the better choice.
What Makes Drizzle Different
The fundamental difference between Drizzle and Prisma is where the schema lives and what the query API looks like.
Prisma defines the schema in a .prisma DSL file and runs a code generation step that produces a TypeScript client. The query API looks like method calls on model objects: prisma.user.findMany({ where: { ... } }).
Drizzle defines the schema directly in TypeScript files and the query API reads like SQL: db.select().from(users).where(eq(users.email, 'user@example.com')). No DSL, no code generation step. The schema is just TypeScript, and the query builder produces SQL strings with full type inference.
This distinction matters in a few ways:
No code generation step. With Prisma, you must run prisma generate after every schema change, and the generated client must be present at runtime. With Drizzle, your schema is just TypeScript that TypeScript understands natively. No generation needed.
Smaller bundle size. Prisma's generated client and the Prisma query engine binary can add megabytes to your bundle. Drizzle's runtime is kilobytes. This is significant for serverless functions where bundle size directly affects cold start latency, and for edge functions where bundle size limits are strict.
Closer to SQL. If you know SQL well, Drizzle's query builder is easier to predict. You write Drizzle and you can mostly picture the SQL it generates. Prisma's API is more abstract and occasionally generates surprising SQL.
Schema Definition
Drizzle schemas are TypeScript files:
import { pgTable, text, boolean, timestamp, uuid } from 'drizzle-orm/pg-core'
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
email: text('email').notNull().unique(),
name: text('name'),
createdAt: timestamp('created_at').defaultNow().notNull(),
})
export const posts = pgTable('posts', {
id: uuid('id').primaryKey().defaultRandom(),
title: text('title').notNull(),
published: boolean('published').default(false).notNull(),
authorId: uuid('author_id').references(() => users.id).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
})
These are just TypeScript objects. Import them, use them in queries, extend them with TypeScript utilities. No separate file format to learn.
The Query Builder
Drizzle's query builder is explicit about what SQL it generates:
Select:
import { db } from './db'
import { users, posts } from './schema'
import { eq, and, desc } from 'drizzle-orm'
const result = await db
.select({ id: users.id, name: users.name, email: users.email })
.from(users)
.where(eq(users.email, 'alice@example.com'))
Join:
const postsWithAuthors = await db
.select({
postId: posts.id,
title: posts.title,
authorName: users.name,
})
.from(posts)
.innerJoin(users, eq(posts.authorId, users.id))
.where(eq(posts.published, true))
.orderBy(desc(posts.createdAt))
.limit(10)
Insert:
const [newUser] = await db
.insert(users)
.values({ email: 'bob@example.com', name: 'Bob' })
.returning()
Update:
await db
.update(posts)
.set({ published: true })
.where(and(eq(posts.id, postId), eq(posts.authorId, userId)))
Delete:
await db.delete(posts).where(eq(posts.id, postId))
Every query returns correctly typed results based on the schema and the select clause. No manual type annotations needed.
Drizzle's Relational Query API
Drizzle also has a higher-level relational query API (similar to Prisma's include) for fetching related records without writing explicit JOINs:
const usersWithPosts = await db.query.users.findMany({
with: { posts: { where: eq(posts.published, true) } },
})
This requires defining relations in a separate relations configuration:
import { relations } from 'drizzle-orm'
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}))
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}))
The relational API is convenient for common cases. The explicit query builder gives you full control for complex queries.
Migrations: drizzle-kit
Drizzle-kit is the companion CLI for managing migrations. drizzle-kit generate compares your TypeScript schema to the current database schema and generates SQL migration files. drizzle-kit migrate applies pending migrations.
npx drizzle-kit generate
npx drizzle-kit migrate
The generated SQL migration files are plain SQL that you commit to version control. Unlike Prisma Migrate's migration format, Drizzle's migrations are just SQL files that you can read, edit, and understand directly.
Supported Databases
Drizzle supports PostgreSQL, MySQL, SQLite, and their variants (Neon, PlanetScale, Turso, Cloudflare D1, Vercel Postgres). Each has a dialect-specific package (drizzle-orm/pg-core, drizzle-orm/mysql-core, drizzle-orm/sqlite-core). The query API is the same across databases; only the schema column types differ.
When Drizzle Beats Prisma
Serverless and edge deployments: Drizzle's small bundle size (no generated engine binary) makes it suitable for Cloudflare Workers, Vercel Edge Functions, and other environments with strict bundle size limits.
Performance-sensitive applications: Drizzle's runtime overhead is lower than Prisma's because it does not route queries through a query engine layer. Benchmarks consistently show Drizzle generating and executing queries faster.
SQL-familiar teams: If your team is comfortable with SQL, Drizzle's SQL-like API requires less mental translation. You write Drizzle and you know what query is running.
Schema-as-code preference: Some teams prefer having the database schema in TypeScript alongside the rest of the codebase, rather than in a separate DSL file.
When Prisma Is Better
Complex relation traversal: Prisma's include is more ergonomic than writing explicit JOINs or Drizzle's relational API for deeply nested queries.
Non-technical team members reading schemas: Prisma's schema DSL is arguably more readable for people who do not write TypeScript.
Prisma Studio: Prisma's built-in database browser is genuinely useful for debugging. Drizzle Studio exists but is less mature.
Keep Reading
- Prisma ORM Guide — Drizzle's main alternative
- Turso SQLite Guide — edge SQLite that pairs well with Drizzle
- Postgres Guide for Developers — the database to use with Drizzle for most projects
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace — chat, projects, time tracking, AI meeting summaries, and invoicing — in one tool. Try it free.