ダウンロード数2倍差:Prismaがなぜ選ばれるのか
はじめに
2020年 ~ 2023年頃、NestJSを使ったAPI開発に携わっていましたが、ORMとしてTypeORMを使用していました。NestJSのドキュメントでもTypeORM押しで、Prismaについては参考情報がある程度の位置づけだったように覚えています。
しかし、2024年頃をさかいに、Prismaのダウンロード数がTypeORMを超え、直近(2025年9月)のダウンロード数では 2倍ぐらい差がついています。
今選ぶべきはPrismaなのでしょうか?この記事では、実際のコード例を交えながら、両者の特徴を詳しく比較したいと思います。
概要比較
項目 | TypeORM | Prisma |
---|---|---|
リリース年 | 2016年 | 2019年 |
定義スタイル | デコレーターベースのクラス | 宣言的スキーマファイル |
ワークフロー | エンティティ駆動 | スキーマ駆動 |
真実の源泉 | TypeScriptエンティティ | schema.prisma |
アプローチ | OOP型(オブジェクト指向) | 関数型寄り |
型安全性 | 一部(崩れやすい箇所あり) | 一貫して高い |
クエリビルダー | 高機能 | シンプル(複雑な場合は工夫が必要) |
IDE支援 | 普通 | 優秀 |
学習コスト | 高 | 低 |
Prismaの主要な利点
1. 一貫した型安全性とIDE支援
これがPrismaの最大の魅力です。TypeORMもジェネリクスを使った型推論は可能ですが、relations指定や生クエリ部分では型崩れが起こりやすいのが実情です。
// Prisma - 型推論が一貫して効く
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: {
select: { title: true, content: true }
}
}
})
// userの型は自動的に推論される:
// User & { posts: { title: string; content: string }[] }
// TypeORM - relations指定は文字列ベースで補完が効かない
const user = await userRepository.findOne({
where: { id: 1 },
relations: ['posts']
})
2. スキーマ駆動の利点
Prismaでは schema.prisma
が単一の真実の源泉となり、DBスキーマ・型・クライアント生成が一貫して行えます。
TypeORMはエンティティクラスごとに分散しがちです。
// Prisma
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
...
}
// TypeORM
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column({ nullable: true })
name: string;
@OneToMany(() => Post, post => post.author)
posts: Post[];
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
3. 優れた開発者体験
Prisma Studio
npx prisma studio
データベースの可視化・編集ツールが標準搭載されており、TypeORMにはこのような統合ツールがありません。
4. パフォーマンスについて
Prisma公式が2024年7月に公開したベンチマーク結果によると、「どのORMが最速か?」という質問に対する答えは「場合による」とされています。実際のクエリ、データセット、スキーマ、実行するインフラによって結果が変わります。
ただし差は数ミリ秒程度であり、ユーザー体験への影響は小さいことが多いです。ORM選択の決め手は性能より開発体験やチーム構成になるでしょう。
5. クエリAPI
- シンプルな読み取り系 → Prismaの方が直感的でIDE補完が効く
- 複雑な結合・集計 → TypeORMのクエリビルダーの方が便利
// Prisma - シンプルな読み取りに強い
const posts = await prisma.post.findMany({
where: {
author: { email: { contains: '@company.com' } },
published: true
},
include: { author: { select: { name: true, email: true } }, tags: true },
orderBy: { createdAt: 'desc' },
take: 10
})
// TypeORM - 複雑な結合・集計に強い
const posts = await postRepository.find({
relations: ['author', 'tags'],
where: { author: { email: Like('%@company.com%') }, published: true },
order: { createdAt: 'DESC' },
take: 10
})
TypeORMの利点(Prismaの弱点)
1. 高い柔軟性
TypeORMのクエリビルダーは複雑な集計や条件分岐に強力です。Prismaも Client Extensions を使えばある程度抽象化できるようですが、込み入った集計は生SQLに頼ることになりそうです。
※Middleware はv4.16.0でdeprecatedとなり、v6.14.0で削除されています。
// TypeORM - 複雑なクエリビルダー
const result = await userRepository
.createQueryBuilder('user')
.leftJoinAndSelect('user.posts', 'posts')
.leftJoinAndSelect('posts.tags', 'tags')
.where('posts.createdAt > :date', { date: lastMonth })
.andWhere('user.status = :status', { status: 'active' })
.andWhere('tags.name IN (:...tagNames)', { tagNames: ['tech', 'javascript'] })
.groupBy('user.id')
.having('COUNT(posts.id) > :minPosts', { minPosts: 5 })
.getMany()
// Prisma - 複雑な場合は生SQLが必要
const result = await prisma.$queryRaw`
SELECT u.*, COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON u.id = p.authorId
LEFT JOIN post_tags pt ON p.id = pt.postId
LEFT JOIN tags t ON pt.tagId = t.id
WHERE p.createdAt > ${lastMonth}
AND u.status = 'active'
AND t.name IN ('tech', 'javascript')
GROUP BY u.id
HAVING COUNT(p.id) > ${minPosts}
`
2. デコレーターベースのバリデーション統合
TypeORMでは class-validator
と自然に組み合わせ可能です。
ただし「DB制約」と「入力バリデーション」を同じ層に書くことは推奨されない場合もあります。
PrismaではDB制約はschemaに、入力バリデーションはZodなどで責務分離する方が一般的です。
// TypeORM + class-validator
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
@IsEmail()
@Length(5, 255)
email: string;
@Column()
@IsOptional()
@Length(1, 100)
name?: string;
}
// Prisma - 別途バリデーションライブラリが必要
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email().min(5).max(255),
name: z.string().min(1).max(100).optional()
});
3. エコシステムの成熟度
- TypeORM: 歴史が長く、プラグインや利用実績が豊富
- Prisma: 近年急速に成長し、既に多くのプロダクションで採用されつつある
4. 生SQLとの親和性
TypeORMはEntityManagerを通じて生SQLとORMクエリを自然に混在させやすいのが特徴です。Prismaでも $queryRaw
を提供していますが、抽象化はTypeORMの方が薄く、より直感的です。
Prisma or TypeORM どっち?
Prismaを選ぶべき場面
✅ 型安全性を最重要視する場合
✅ 迅速な開発を優先する場合
✅ 現代的なツールを使いたい場合
TypeORMを選ぶ/継続すべき場面
✅ 複雑なクエリが多いシステム
✅ 最大限の柔軟性が必要な場合
✅ デコレーターベースのバリデーション統合を重視している場合
まとめ
PrismaとTypeORMはそれぞれ異なる哲学を持つ優秀なORMです:
- Prisma: 現代的で型安全、開発者体験重視
- TypeORM: 柔軟で歴史が長く、利用実績が豊富
2025年現在どうする?:
- 新規プロジェクト → Prisma(かな?)
- 既存システム → TypeORM継続か段階的移行を検討
- 学習コストを抑えたい → Prisma
- 複雑なクエリ中心 → TypeORM
Discussion
私の観測範囲では Drizzle や Kysely も流行っていますね。
抽象的 <- Prisma - Drizzle - Kysely -> SQL 寄り
というイメージです。複雑なクエリが多いシステムは Drizzle や Kysely が今後の選択肢になりそうですね。
TypeORM にはちょっと限界を感じています。
コメントありがとうございます!Drizzleは聞いたことありましたが、Kyselyは未認知でした。頂いた位置づけとダウンロード数見ると、Drizzle良さそうですね。見てみたいと思います!
Kysely はあまり知られていませんが、これも注目されて欲しいな〜と思っています。
クエリビルダーだけの小さなパッケージ、でも最強の型補完を提供してくれます。
prisma や drizzle のスキーマを読み込む方法もあるので、足りないところを補う形でも利用できます。