Skip to main content

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

PackageWeekly DownloadsYoY 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

BoilerplateORMWhy
ShipFastDrizzleSwitched 2024 for performance
T3 StackBoth (your choice)Supports either via CLI
MakerkitPrismaEstablished, team comfort
SupastarterPrismaSupabase Prisma adapter
Open SaaSPrismaWasp uses Prisma
Epic StackPrismaKent Dodds prefers Prisma
SaaSrock (Remix)PrismaMature ecosystem
Better Auth starterDrizzle or PrismaSupports 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.

Comments