Why Drizzle Over Prisma

January 25, 2025 · Magnus Rødseth

architecturedrizzleprismadatabaseopinion

Why Drizzle Over Prisma

The TypeScript ORM landscape has a clear incumbent: Prisma. With its schema-first approach and excellent developer experience, Prisma shaped how a generation of developers think about database access.

But a challenger has emerged. Drizzle ORM takes a fundamentally different approach — and for Eden Stack, that approach won. Here's why.

Two Philosophies of Database Access

Prisma and Drizzle represent two distinct philosophies:

Prisma's philosophy: "Developers shouldn't need to think in SQL. Give them a high-level abstraction, and we'll generate the optimal queries."

Drizzle's philosophy: "If you know SQL, you know Drizzle. Stay close to the metal, with TypeScript safety on top."

Neither philosophy is wrong. They optimize for different priorities.

Prisma: The Abstraction Layer

Prisma has earned its popularity. The developer experience is genuinely excellent:

// Prisma: Schema-first, abstracted queries
// schema.prisma
model User {
  id    String @id @default(uuid())
  email String @unique
  posts Post[]
}
 
model Post {
  id       String @id @default(uuid())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId String
}
 
// Query
const usersWithPosts = await prisma.user.findMany({
  include: { posts: true },
});

What Prisma does well:

  • Exceptional developer experience for common patterns
  • Schema-first design with automatic migrations
  • Powerful Prisma Studio for visual database exploration
  • Large ecosystem and community
  • Great documentation

If you're building a straightforward CRUD application and want maximum abstraction from SQL, Prisma delivers.

Where Prisma Struggles

But Prisma's abstraction comes with costs:

1. Bundle Size and Cold Starts

Prisma requires a runtime query engine — a compiled binary that adds significant weight:

MetricPrismaDrizzle
Bundle size~9MB+~7.4KB
Cold start impactSignificantNegligible
DependenciesExternal binaryZero runtime deps

For serverless deployments where cold starts matter, this difference is substantial. Every Lambda invocation, every edge function, every Cloudflare Worker pays this tax.

2. The N+1 Query Problem

Prisma's include syntax is convenient but can hide performance issues:

// This looks innocent
const users = await prisma.user.findMany({
  include: { posts: { include: { comments: true } } },
});
 
// But may generate multiple queries under the hood

Prisma has improved here, but the abstraction can make it harder to reason about what's actually hitting your database.

3. Code Generation Dependency

Prisma requires a generate step. Change your schema, run prisma generate, wait for codegen. It works, but it's friction — and it means your types exist in a generated file, not in your source code.

Drizzle: SQL With Type Safety

Drizzle takes the opposite approach: your schema IS TypeScript, your queries look like SQL, and there's no abstraction hiding what happens.

// Drizzle: TypeScript-first, SQL-aware
import { pgTable, uuid, varchar, text } from 'drizzle-orm/pg-core';
 
export const users = pgTable('users', {
  id: uuid('id').defaultRandom().primaryKey(),
  email: varchar('email', { length: 255 }).unique().notNull(),
});
 
export const posts = pgTable('posts', {
  id: uuid('id').defaultRandom().primaryKey(),
  title: varchar('title', { length: 255 }).notNull(),
  authorId: uuid('author_id').references(() => users.id).notNull(),
});
 
// Query — looks like SQL, fully typed
const usersWithPosts = await db
  .select()
  .from(users)
  .leftJoin(posts, eq(posts.authorId, users.id));

Why "If You Know SQL, You Know Drizzle" Matters

Here's the key insight: SQL is a feature, not a bug.

SQL has been refined for 50 years. It's declarative, powerful, and universally understood. When you write a Drizzle query, you can predict exactly what SQL it generates — because the syntax maps directly.

// What you write
const result = await db
  .select({
    userName: users.name,
    postCount: count(posts.id),
  })
  .from(users)
  .leftJoin(posts, eq(posts.authorId, users.id))
  .groupBy(users.id)
  .having(gt(count(posts.id), 5));
 
// What runs (predictable)
// SELECT users.name, COUNT(posts.id)
// FROM users
// LEFT JOIN posts ON posts.author_id = users.id
// GROUP BY users.id
// HAVING COUNT(posts.id) > 5

For developers who know SQL, this is liberating. No guessing what the ORM will generate. No wondering why a query is slow. The translation is transparent.

Performance Where It Counts

Benchmarks consistently show Drizzle outperforming Prisma, especially in scenarios that matter for modern apps:

BenchmarkDrizzlePrisma
Simple select~2-3x fasterBaseline
Complex joins~2-4x fasterBaseline
Cold start~10x fasterBaseline
Bundle size7.4KB~9MB

The cold start advantage is particularly relevant for:

  • Serverless functions — Every Lambda, Vercel function, or edge handler benefits
  • Edge deployments — Cloudflare Workers, Deno Deploy, etc.
  • Microservices — Fast container startup times

Type Safety Without Code Generation

Drizzle's type inference works at compile time, without generating files:

// Your schema defines the types
export const users = pgTable('users', {
  id: uuid('id').defaultRandom().primaryKey(),
  email: varchar('email', { length: 255 }).notNull(),
  role: varchar('role', { length: 50 }).$type<'admin' | 'user'>(),
});
 
// Types are inferred
type User = typeof users.$inferSelect;
// { id: string; email: string; role: 'admin' | 'user' | null }
 
type NewUser = typeof users.$inferInsert;
// { id?: string; email: string; role?: 'admin' | 'user' | null }

No prisma generate. No watching for schema changes. Your TypeScript just works.

Relational Queries When You Want Them

Drizzle also offers a higher-level Queries API for when you want Prisma-style convenience:

// Drizzle Queries API — more abstract when needed
const usersWithPosts = await db.query.users.findMany({
  with: {
    posts: {
      with: { comments: true },
    },
  },
});

Best of both worlds: SQL-like precision when you need control, relational convenience when you don't.

The Provider-Agnostic Advantage

Here's something often overlooked: Drizzle makes your database choice a configuration detail.

// Switch from Neon to local Postgres to AWS RDS
// by changing one line
import { drizzle } from 'drizzle-orm/neon-http';
// or
import { drizzle } from 'drizzle-orm/postgres-js';
// or
import { drizzle } from 'drizzle-orm/node-postgres';

Your schema stays the same. Your queries stay the same. The infrastructure is abstracted at the driver level, not the query level. This matters when:

  • You want local Docker development with Neon production
  • You might migrate to a different PostgreSQL host
  • You need different drivers for different deployment targets

When to Choose What

Choose Prisma when:

  • Your team prefers maximum abstraction from SQL
  • You're building straightforward CRUD applications
  • Prisma Studio is valuable for your workflow
  • Bundle size and cold starts aren't concerns
  • You like schema-first development with separate files

Choose Drizzle when:

  • You're comfortable with SQL and want that control
  • Serverless/edge performance matters
  • You prefer schema-as-code in TypeScript
  • You want minimal bundle size
  • Provider flexibility is important

Why Eden Stack Uses Drizzle

For a template designed around TypeScript excellence and deployment flexibility, Drizzle was the clear choice:

  1. TypeScript-native — Schema defined in TypeScript, types inferred automatically
  2. Performance — Fast queries, tiny bundle, serverless-optimized
  3. SQL transparency — Know exactly what's hitting your database
  4. Provider flexibility — Works with Neon, local Postgres, or any PostgreSQL host
  5. Modern approach — Built for the serverless era, not adapted to it

Combined with Neon for serverless PostgreSQL, Drizzle provides the database layer Eden Stack needs: type-safe, performant, and infinitely flexible.

The result is a stack where your database access is as transparent as your API types — you always know what's happening, and TypeScript has your back.


This post reflects my opinions after building with both Prisma and Drizzle in production. Prisma is an excellent tool that has served the community well — this isn't about Prisma being bad, but about Drizzle being a better fit for Eden Stack's goals.

Ready to build with Eden Stack?

One-time payment. Full source code. No lock-in.

View pricing