文章

Prisma vs Drizzle vs TypeORM:2025年Node.js ORM选型指南

一篇面向工程团队的实用对比:Prisma、Drizzle 和 TypeORM 在类型安全、性能、迁移工作流及 SaaS 场景中的真实表现。

选错 ORM 的代价,后期修复起来非常昂贵。在将生产级 Node.js SaaS 产品全部用这三种 ORM 交付后,这里是一份诚实的对比。

参赛选手

PrismaDrizzleTypeORM
星标数 (2025)40k+25k+34k+
首次发布201920222016
查询风格Schema DSL类 SQL APIActive Record / Data Mapper
运行时Node.js + 边缘*Node.js + 边缘Node.js
迁移Prisma MigrateDrizzle Kit内置 / TypeORM CLI

Prisma

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
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}
// 每次查询都是完全类型化的
const user = await prisma.user.findUnique({
  where: { email: "[email protected]" },
  include: { posts: { where: { published: true } } }
});
// user: { id: number; email: string; posts: Post[]; ... } | null

迁移在 Prisma 中是头等公民。你编辑 schema,运行 prisma migrate dev,就会得到一个版本化的 SQL 迁移文件并提交到源码管理。prisma migrate deploy 在 CI/CD 中应用待处理的迁移。

优势:

  • 最佳的开发者体验和自动补全
  • 优秀的文档和庞大的社区
  • Prisma Studio 用于可视化数据浏览
  • 通过中间件内置软删除/审计日志

劣势:

  • Prisma 引擎作为独立的 sidecar 二进制文件运行——在无服务器环境中增加冷启动延迟和内存开销
  • 无法完全退回到原始 SQL 而不丢失类型安全(使用 $queryRaw 配合 Prisma.sql 模板标签)
  • Schema DSL 是另一种需要学习的语言

何时使用 Prisma: 当你希望为整天编写 TypeScript 的团队提供最流畅的 DX,你不在边缘环境中,并且你重视迁移工作流。

Drizzle

Drizzle 在 TypeScript 中定义 schema,而不是使用单独的 DSL。查询使用一个紧密模仿 SQL 的构建器 API 编写。

import { pgTable, serial, text, boolean, integer, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  email: text("email").notNull().unique(),
  name: text("name"),
  createdAt: timestamp("created_at").defaultNow().notNull()
});

export const posts = pgTable("posts", {
  id: serial("id").primaryKey(),
  title: text("title").notNull(),
  published: boolean("published").default(false).notNull(),
  authorId: integer("author_id").references(() => users.id).notNull()
});
// 类 SQL,完全类型化
const usersWithPosts = await db
  .select()
  .from(users)
  .leftJoin(posts, eq(posts.authorId, users.id))
  .where(eq(users.email, "[email protected]"));

Drizzle 生成纯 SQL,没有中间引擎,使其非常适合 Cloudflare Workers、Vercel Edge Functions 和低延迟的无服务器环境。

迁移使用 drizzle-kit

pnpm drizzle-kit generate  # 比较 schema 与数据库 → 输出 SQL 迁移
pnpm drizzle-kit migrate   # 应用待处理的迁移

优势:

  • 无 sidecar 二进制文件——可在任何 JavaScript 运行的地方运行(边缘、无服务器、Bun、Deno)
  • 最薄的抽象层:如果你懂 SQL,你就懂 Drizzle
  • 原始查询基准测试中最快
  • 包含 Drizzle Studio

劣势:

  • 生态较年轻——第三方插件较少
  • 迁移工具不如 Prisma 完善(但改进迅速)
  • 复杂连接的学习曲线高于 Prisma 的 includes

何时使用 Drizzle: 当你需要边缘运行时支持,想要对 SQL 的最小抽象,或者你的团队习惯编写原始 SQL 并希望获得类型化结果。

TypeORM

TypeORM 早于 TypeScript 严格模式的改进,显得有些过时。它使用装饰器定义实体:

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column({ nullable: true })
  name: string;
}

@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ default: false })
  published: boolean;

  @ManyToOne(() => User, user => user.posts)
  author: User;
}

TypeORM 支持两种模式:Active Record(实体拥有 .save().find() 方法)和 Data Mapper(由仓库执行工作)。Data Mapper 模式与 NestJS 等依赖注入框架集成得更好。

优势:

  • 最成熟——庞大的生态系统,大量教程
  • 原生 NestJS 集成
  • 支持最广泛的数据库(包括 MongoDB)

劣势:

  • 装饰器元数据需要 reflect-metadata shim 和特定的 tsconfig 设置
  • 严格的 TypeScript 支持不完整——某些查询返回 any
  • 在急加载中存在 N+1 查询问题的活跃 issue
  • 开发速度慢于 Prisma / Drizzle

何时使用 TypeORM: 当你使用 NestJS 构建并希望获得框架原生集成,或者你在扩展现有的 TypeORM 代码库。

性能对比

对于典型的 SaaS 读取端点(获取用户 + 5 个关联):

ORM冷启动 (Lambda)P99 查询时间
Drizzle~5ms~2ms
Prisma (引擎已缓存)~15ms~4ms
Prisma (冷启动)~120ms~4ms
TypeORM~20ms~5ms

Prisma 的冷启动惩罚在无服务器环境中最为明显。在长时间运行的 Node.js 进程(EC2、Railway、Fly.io)中,Prisma 的引擎已经预热,性能差距会缩小。

决策矩阵

场景推荐
基于 VPS/容器的 NestJS 单体应用Prisma 或 TypeORM
使用 Vercel 或 Cloudflare 的 Next.js / Remix 应用Drizzle
基于 Lambda 的微服务Drizzle
团队偏好 SQL,讨厌 DSLDrizzle
追求极致 DX,团队级自动补全Prisma
现有 NestJS + TypeORM 代码库保留 TypeORM

迁移路径

如果你正在使用 TypeORM 并考虑切换,Drizzle 更容易迁移,因为两者都使用显式 SQL。Prisma 需要先重写为其 schema DSL。

推荐的迁移方法:

  1. 在非关键服务上并行运行两个 ORM
  2. 在预发布环境中比较查询输出
  3. 一次迁移一个服务,从读取密集型服务开始,Drizzle 的速度优势在此显现
  4. 在写入密集型服务上保留 TypeORM,直到你建立信心

常见问题

Drizzle 比 Prisma 快吗?
在基准测试中,Drizzle 在原始查询上优于 Prisma,因为它生成更直接的 SQL,没有 Prisma 查询引擎进程的开销。对于大多数 SaaS 应用,这种差异并非瓶颈,但 Drizzle 的边缘运行时支持(Cloudflare Workers、Vercel Edge)在需要时是一个决定性优势。
2025年 TypeORM 还值得用吗?
TypeORM 成熟且广泛使用,但积累了一些技术债务,并且与 TypeScript 严格模式存在兼容性问题。对于新项目,Prisma 或 Drizzle 通常是更好的选择。对于现有 TypeORM 代码库,迁移并不紧迫——该库仍在维护且功能正常。
Prisma 能配合 PlanetScale 或 Neon 使用吗?
可以。Prisma 通过 planetscale 适配器支持 PlanetScale,通过 @prisma/adapter-neon 支持 Neon。Drizzle 也支持两者。PlanetScale 的分支模型与 Prisma 的迁移工作流配合良好,你可以使用 prisma migrate diff 生成分支特定的迁移。