🐥

ダウンロード数2倍差:Prismaがなぜ選ばれるのか

に公開3

はじめに

2020年 ~ 2023年頃、NestJSを使ったAPI開発に携わっていましたが、ORMとしてTypeORMを使用していました。NestJSのドキュメントでもTypeORM押しで、Prismaについては参考情報がある程度の位置づけだったように覚えています。

しかし、2024年頃をさかいに、Prismaのダウンロード数がTypeORMを超え、直近(2025年9月)のダウンロード数では 2倍ぐらい差がついています。

今選ぶべきはPrismaなのでしょうか?この記事では、実際のコード例を交えながら、両者の特徴を詳しく比較したいと思います。

2024年に逆転

https://npmtrends.com/prisma-vs-typeorm

概要比較

項目 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

somnicattussomnicattus

私の観測範囲では Drizzle や Kysely も流行っていますね。

抽象的 <- Prisma - Drizzle - Kysely -> SQL 寄り というイメージです。

複雑なクエリが多いシステムは Drizzle や Kysely が今後の選択肢になりそうですね。

TypeORM にはちょっと限界を感じています。

duckdevvduckdevv

コメントありがとうございます!Drizzleは聞いたことありましたが、Kyselyは未認知でした。頂いた位置づけとダウンロード数見ると、Drizzle良さそうですね。見てみたいと思います!

somnicattussomnicattus

Kysely はあまり知られていませんが、これも注目されて欲しいな〜と思っています。
クエリビルダーだけの小さなパッケージ、でも最強の型補完を提供してくれます。

prisma や drizzle のスキーマを読み込む方法もあるので、足りないところを補う形でも利用できます。