Drizzle vs Prisma in 2026 Boilerplates: Which ORM Won
·StarterPick Team
drizzleprismaormdatabasesaas-boilerplatetypescript2026
TL;DR
Prisma still leads in boilerplate adoption, but Drizzle is gaining fast. ShipFast moved to Drizzle in 2024. T3 Stack supports both. Makerkit and Supastarter still default to Prisma. The npm data tells the story: Drizzle's weekly downloads grew 3x in 2025 while Prisma stayed flat. Drizzle wins on performance and SQL control; Prisma wins on DX, documentation, and ecosystem maturity. For new projects in 2026: Drizzle is the better technical choice; Prisma is the safer community bet.
Key Takeaways
- Prisma: 4.8M downloads/week, schema-first, excellent DX, slower query performance
- Drizzle: 2.1M downloads/week growing fast, SQL-first, better performance, ~60KB vs Prisma's ~5MB
- Boilerplate adoption: ShipFast → Drizzle; T3 → both; Makerkit → Prisma; Supastarter → Prisma
- Performance: Drizzle is 2-4x faster on simple queries; ~equal on complex joins
- Migration DX: Prisma Migrate is simpler; Drizzle requires more SQL knowledge
- Type safety: both excellent; Drizzle's is more granular
npm Download Trends
| Package | Weekly Downloads | YoY Growth |
|---|---|---|
prisma (CLI) | ~4.8M | +5% |
@prisma/client | ~4.6M | +5% |
drizzle-orm | ~2.1M | +180% |
drizzle-kit | ~1.8M | +200% |
Drizzle's growth trajectory is the story of 2025-2026.
Prisma: Schema-First, Excellent DX
// schema.prisma — human-readable schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String?
plan String @default("free")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
posts Post[]
subscription Subscription?
}
model Post {
id String @id @default(cuid())
title String
content String
published Boolean @default(false)
authorId String
createdAt DateTime @default(now())
author User @relation(fields: [authorId], references: [id])
}
// Prisma Client queries:
const usersWithPosts = await db.user.findMany({
where: { plan: 'pro' },
include: {
posts: {
where: { published: true },
orderBy: { createdAt: 'desc' },
take: 5,
},
subscription: true,
},
});
// Aggregate query:
const stats = await db.post.aggregate({
where: { published: true },
_count: { id: true },
_avg: { views: true },
});
Drizzle: SQL-First, Performance-Optimized
// schema.ts — TypeScript-first schema definition
import { pgTable, text, boolean, timestamp, integer } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: text('id').primaryKey().$defaultFn(() => createId()),
email: text('email').notNull().unique(),
name: text('name'),
plan: text('plan').notNull().default('free'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().$onUpdate(() => new Date()).notNull(),
});
export const posts = pgTable('posts', {
id: text('id').primaryKey().$defaultFn(() => createId()),
title: text('title').notNull(),
content: text('content').notNull(),
published: boolean('published').default(false).notNull(),
authorId: text('author_id').notNull().references(() => users.id),
createdAt: timestamp('created_at').defaultNow().notNull(),
});
// Types inferred automatically:
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
// Drizzle queries — close to SQL, fully typed:
import { db } from './db';
import { users, posts } from './schema';
import { eq, and, desc, count } from 'drizzle-orm';
// Join query:
const usersWithPosts = await db
.select({
user: users,
postCount: count(posts.id),
})
.from(users)
.leftJoin(posts, eq(posts.authorId, users.id))
.where(eq(users.plan, 'pro'))
.groupBy(users.id)
.orderBy(desc(users.createdAt))
.limit(50);
// Raw SQL when needed (escape hatch):
const result = await db.execute(sql`
SELECT u.*, COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON p.author_id = u.id
GROUP BY u.id
`);
Which Boilerplates Use What
| Boilerplate | ORM | Why |
|---|---|---|
| ShipFast | Drizzle | Switched 2024 for performance |
| T3 Stack | Both (your choice) | Supports either via CLI |
| Makerkit | Prisma | Established, team comfort |
| Supastarter | Prisma | Supabase Prisma adapter |
| Open SaaS | Prisma | Wasp uses Prisma |
| Epic Stack | Prisma | Kent Dodds prefers Prisma |
| SaaSrock (Remix) | Prisma | Mature ecosystem |
| Better Auth starter | Drizzle or Prisma | Supports both |
Performance Reality
Simple SELECT query (1 row by primary key):
Drizzle: ~0.5ms
Prisma: ~1.2ms
Complex JOIN (5 tables, 1000 rows):
Drizzle: ~8ms
Prisma: ~12ms (generates optimal SQL too)
Bulk INSERT (1000 rows):
Drizzle: ~15ms
Prisma: ~45ms (Prisma uses individual inserts)
Memory usage:
Drizzle client: ~60KB
Prisma client: ~5MB (ships query engine binary)
Decision Guide
Choose Prisma if:
→ Team is new to ORMs (better docs, tutorials)
→ Using Prisma Migrate for zero-downtime migrations
→ Existing Prisma codebase
→ Need the studio GUI for non-technical users
Choose Drizzle if:
→ Performance-sensitive application
→ Team comfortable with SQL
→ Serverless deployment (smaller cold starts)
→ Edge runtime required (Drizzle supports edge, Prisma doesn't fully)
→ ShipFast-style boilerplate architecture
Compare Drizzle and Prisma package health scores on StarterPick.