Prisma 和 Drizzle 对比
9月 24, 2025
Prisma 和 Drizzle 确实是同类工具,它们都属于 现代 TypeScript/JavaScript ORM(对象关系映射),但在设计哲学、功能特性和使用方式上有显著差异。
核心定位对比#
| 特性 | Prisma | Drizzle |
|---|---|---|
| 类型安全 | 🔥 强类型,自动生成 TypeScript 类型 | 🔥 强类型,基于 TypeScript 推断 |
| 查询语法 | 声明式,类 GraphQL 风格 | 类 SQL 的表达式语法 |
| 架构定义 | 专属的 .prisma schema 文件 | TypeScript 代码定义或配置文件 |
| 迁移管理 | 内置完整的迁移系统 | 支持迁移,但更灵活 |
| 运行时大小 | 较大(~1.5MB) | 轻量(~20KB) |
| 学习曲线 | 中等,需要学习 Prisma 特有语法 | 较低,对 SQL 用户友好 |
代码示例对比#
1. 架构定义#
Prisma Schema:
// schema.prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}Drizzle Schema:
// schema.ts
import { pgTable, serial, varchar, boolean, integer, timestamp } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: varchar('email', { length: 255 }).unique().notNull(),
name: varchar('name', { length: 255 }),
createdAt: timestamp('created_at').defaultNow(),
});
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: varchar('title', { length: 255 }).notNull(),
content: varchar('content', { length: 1000 }),
published: boolean('published').default(false),
authorId: integer('author_id').references(() => users.id),
});2. 查询语法对比#
Prisma 查询:
// 声明式,类似 GraphQL
const userWithPosts = await prisma.user.findUnique({
where: { email: 'user@example.com' },
include: {
posts: {
where: { published: true },
select: { title: true, createdAt: true }
}
}
});Drizzle 查询:
// 类 SQL 的表达式语法
import { eq, and, desc } from 'drizzle-orm';
const userWithPosts = await db
.select({
user: users,
posts: {
title: posts.title,
createdAt: posts.createdAt
}
})
.from(users)
.leftJoin(posts, eq(users.id, posts.authorId))
.where(
and(
eq(users.email, 'user@example.com'),
eq(posts.published, true)
)
)
.orderBy(desc(posts.createdAt));主要差异深度分析#
1. 设计哲学#
- Prisma: “数据库客户端”,提供高层抽象,隐藏 SQL 细节
- Drizzle: “类型安全的 SQL 查询构建器”,更接近原生 SQL
2. 类型安全实现#
- Prisma: 通过代码生成器自动生成完整的 TypeScript 类型
- Drizzle: 利用 TypeScript 的泛型和类型推断,无代码生成
3. 关系处理#
// Prisma - 自动处理关系
await prisma.user.create({
data: {
email: 'test@example.com',
posts: {
create: [
{ title: 'Post 1', content: '...' },
{ title: 'Post 2', content: '...' }
]
}
}
});
// Drizzle - 需要显式处理关系(事务)
await db.transaction(async (tx) => {
const [user] = await tx.insert(users).values({
email: 'test@example.com'
}).returning();
await tx.insert(posts).values([
{ title: 'Post 1', authorId: user.id },
{ title: 'Post 2', authorId: user.id }
]);
});选择建议#
选择 Prisma 的情况:#
- ✅ 团队偏好声明式 API
- ✅ 需要完整的迁移管理系统
- ✅ 项目复杂度高,需要强大的关系处理
- ✅ 与非技术成员协作(Prisma Studio 很友好)
选择 Drizzle 的情况:#
- ✅ 团队熟悉 SQL,希望更直接的掌控力
- ✅ 对包大小敏感(边缘计算、Serverless)
- ✅ 需要高度定制化的查询优化
- ✅ 偏好零代码生成的开发体验
性能考虑:#
// Drizzle 在复杂查询中通常有更好性能
const analytics = await db
.select({
userId: users.id,
postCount: sql<number>`count(${posts.id})`,
lastPost: sql<string>`max(${posts.createdAt})`
})
.from(users)
.leftJoin(posts, eq(users.id, posts.authorId))
.groupBy(users.id)
.having(gt(sql`count(${posts.id})`, 5));实际项目配置示例#
Prisma 项目设置:#
// prisma/client.ts
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma;
}Drizzle 项目设置:#
// lib/db.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL!
});
export const db = drizzle(pool, { schema });
// 类型导出用于前端
export type * from './schema';总结#
Prisma 和 Drizzle 都是优秀的现代 ORM,但它们面向不同的使用场景和开发者偏好:
- Prisma 更适合追求开发效率、需要完整解决方案的团队
- Drizzle 更适合追求性能、控制力和轻量级的场景
两者都在快速发展中,选择时建议考虑团队的技术栈偏好、性能需求和长期维护成本。