Back

2026年版 Drizzle ORM vs Prisma:誰もやらない本音の比較

2026年にTypeScriptでバックエンドを書いていると、いずれ必ずこの問いにぶつかります。DrizzleかPrismaか?

ネット上の意見は極端なものばかりです。「Prismaは重い」「Drizzleは生SQLにラッパーかぶせただけ」「Prismaのエンジンはやりすぎ」「Drizzleのマイグレーションは未熟」。こうした声のほとんどは、情報が古いか、一面的か、そもそも間違っています。Prisma 7がエンジンをTypeScriptで一から書き直し、批判の根拠だったRustバイナリを完全に廃止した今となっては、なおさらです。

この記事は一味違います。本当に重要な軸すべてで比較していきます。クエリ性能、コールドスタート、バンドルサイズ、型安全性、マイグレーション、エッジ互換性、そして実際の開発体験。特定のORM推しもなければ、スポンサー付きの結論もありません。データと率直な分析だけです。

最後まで読めば、「自分のプロジェクトにはどちらが合うか」が明確になるはずです。そして、なぜそうなのかも。

根本的な設計思想の違い

ベンチマークの前に、DrizzleとPrismaの設計思想がどう違うかを押さえておく必要があります。単なる実装の違いではなく、あらゆる判断に影響する根本的な分岐点です。

Prisma抽象化ファースト.prismaという独自DSLでスキーマを書くと、型安全なクライアントが自動生成されます。SQLは意図的に隠されています。「SQLのことは考えなくていい。データモデルさえ記述すれば、あとは任せてほしい」という思想です。

DrizzleSQLファースト。TypeScriptでスキーマを定義しますが、使う関数はSQL構造をそのまま反映しています。「SQLを知っていればDrizzleはもう使える。データベースを隠すのではなく、型安全なSQLを提供する」という思想です。

要するに:

  • Prismaユーザーはモデルとリレーションで考える
  • DrizzleユーザーはテーブルとJOINで考える

どちらが正解というわけではありません。ただし、この違いがこれから話すすべてに波及します。

スキーマ定義:2つの世界

Prismaのスキーマ

Prismaは独自DSLを使います:

model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] profile Profile? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Post { id Int @id @default(autoincrement()) title String content String? published Boolean @default(false) author User @relation(fields: [authorId], references: [id]) authorId Int tags Tag[] createdAt DateTime @default(now()) } model Tag { id Int @id @default(autoincrement()) name String @unique posts Post[] } model Profile { id Int @id @default(autoincrement()) bio String? user User @relation(fields: [userId], references: [id]) userId Int @unique }

見た目はすっきりしていて、宣言的で読みやすいです。リレーションがモデルレベルで定義されているので、全体像がひと目でわかります。構文も簡潔で、ほぼドキュメント不要です。

ただし代償があります。これはTypeScriptではありません。スキーマが専用の構文・拡張子・ツールチェーンを持つ別ファイルに存在します。VS Code拡張でIDEサポートはありますが、ネイティブのTypeScript IntelliSenseには及びません。

Drizzleのスキーマ

DrizzleはピュアTypeScriptでスキーマを書きます:

import { pgTable, serial, text, boolean, integer, timestamp } from 'drizzle-orm/pg-core'; import { relations } from 'drizzle-orm'; export const users = pgTable('users', { id: serial('id').primaryKey(), email: text('email').notNull().unique(), name: text('name'), createdAt: timestamp('created_at').defaultNow().notNull(), updatedAt: timestamp('updated_at').defaultNow().notNull(), }); export const posts = pgTable('posts', { id: serial('id').primaryKey(), title: text('title').notNull(), content: text('content'), published: boolean('published').default(false).notNull(), authorId: integer('author_id').references(() => users.id).notNull(), createdAt: timestamp('created_at').defaultNow().notNull(), }); export const tags = pgTable('tags', { id: serial('id').primaryKey(), name: text('name').notNull().unique(), }); export const profiles = pgTable('profiles', { id: serial('id').primaryKey(), bio: text('bio'), userId: integer('user_id').references(() => users.id).notNull().unique(), }); // リレーション定義(クエリAPI用) export const usersRelations = relations(users, ({ many, one }) => ({ posts: many(posts), profile: one(profiles), })); export const postsRelations = relations(posts, ({ one, many }) => ({ author: one(users, { fields: [posts.authorId], references: [users.id] }), tags: many(tags), }));

記述量は確かに増えます。でもこれはピュアTypeScriptです。IntelliSenseがフルに使えて、どこからでもimportでき、lint・format・リファクタリングも拡張なしでそのまま動きます。

トレードオフは明確です: Prismaは簡潔で読みやすい。Drizzleはポータブルで組み合わせ自在。

クエリAPI:真価が問われる場面

2つのORMが最も大きく分かれるポイントです。

シンプルなクエリ

Prisma:

const user = await prisma.user.findUnique({ where: { email: '[email protected]' }, include: { posts: true, profile: true }, });

Drizzle(Query API):

const user = await db.query.users.findFirst({ where: eq(users.email, '[email protected]'), with: { posts: true, profile: true }, });

Drizzle(SQL-like API):

const user = await db .select() .from(users) .where(eq(users.email, '[email protected]')) .leftJoin(posts, eq(posts.authorId, users.id)) .leftJoin(profiles, eq(profiles.userId, users.id));

シンプルなクエリでは開発体験にほぼ差がありません。DrizzleにはリレーショナルAPI(Prismaに近い感覚)とSQL-like API(型安全なクエリビルダー)の2つがあります。

複雑なクエリ:ここで差がつく

面白くなるのは複雑なクエリです。たとえば「過去30日以内に登録したユーザーのうち、publishedなポストがあるユーザーを、ポスト数順でページネーション付きで取得する」という要件を考えてみましょう。

Prisma:

const results = await prisma.user.findMany({ where: { createdAt: { gte: thirtyDaysAgo }, posts: { some: { published: true } }, }, include: { posts: { where: { published: true }, orderBy: { createdAt: 'desc' }, }, _count: { select: { posts: true } }, }, orderBy: { posts: { _count: 'desc' } }, skip: page * pageSize, take: pageSize, });

Drizzle:

const results = await db .select({ user: users, postCount: sql<number>`count(${posts.id})`.as('post_count'), }) .from(users) .leftJoin(posts, and( eq(posts.authorId, users.id), eq(posts.published, true), )) .where(gte(users.createdAt, thirtyDaysAgo)) .groupBy(users.id) .orderBy(desc(sql`post_count`)) .limit(pageSize) .offset(page * pageSize);

ここで設計思想の違いが肌で感じられます:

  • Prismaのクエリはより抽象的です。「publishedなポストがあるユーザーを探す」という概念で発想します。ただし_countやネストincludeを見ると、Prisma独自のパターンを覚える必要があることがわかります。

  • Drizzleのクエリは、自分が書くであろうSQLとほぼ同じです。SQLがわかる人なら即座に読めます。ただしGROUP BYLEFT JOINといったSQL概念の知識は前提になります。

生SQLへの脱出口

どちらも生SQLに対応していますが、使い心地が違います:

Prisma:

const result = await prisma.$queryRaw` SELECT u.*, COUNT(p.id) as post_count FROM "User" u LEFT JOIN "Post" p ON p."authorId" = u.id WHERE p.published = true GROUP BY u.id ORDER BY post_count DESC `; // ⚠️ 戻り値の型は`unknown`

Drizzle:

const result = await db.execute(sql` SELECT ${users.id}, ${users.email}, COUNT(${posts.id}) as post_count FROM ${users} LEFT JOIN ${posts} ON ${posts.authorId} = ${users.id} WHERE ${posts.published} = true GROUP BY ${users.id} ORDER BY post_count DESC `); // ✅ テーブル・カラム参照は型チェックされたまま

Drizzleのsqlテンプレートタグでは、生SQLの中でもスキーマオブジェクトを参照でき、部分的に型安全性が維持されます。Prismaの$queryRawは完全にノータイプです。

パフォーマンス:2026年の実測値

みんなが一番知りたい部分でしょう。そして2026年に状況が激変しました。

Prisma 7という転換点

2026年より前のベンチマークに基づいた印象は、もう使えません。Prisma 7がクエリエンジンを完全に作り直しました。Rustベースのエンジンを廃止し、TypeScript/WebAssemblyのQuery Compilerに置き換えたのです。この一つの変更が、パフォーマンス論争の前提を覆しました:

  • 旧Rustバイナリは~14MB。新TS/WASMエンジンは~1.6MB(gzip時600KB)。85-90%の削減
  • JS⇔Rust間のシリアライゼーションオーバーヘッドが消滅し、大量データセットで最大3.4倍高速化
  • サーバーレスのコールドスタートが最大9倍改善

過去のPrismaパフォーマンス批判の多くが、もはや当てはまりません。

クエリ実行性能

ほとんどのベンチマークが見落としている点があります。ORM層がボトルネックになることはめったにありません。まともなクエリなら、データベース側の実行時間がORM層のオーバーヘッドを圧倒します。

とはいえ、2026年時点で測定できる差はあります:

指標Prisma 7.xDrizzle 0.45.x
シンプルなfindOne~1-2ms~0.5-1ms
複雑なJOINクエリ~2-5ms~1-3ms
大量結果セット(1000+行)大幅改善(Prisma 6比3.4倍)もとから高速
生SQLパススルー~0.5ms~0.3ms

DrizzleはORMオーバーヘッド単体では依然として速いです。エンジン層なしでSQL文字列を直接生成するためです。ただしPrisma 7で差はかなり縮まりました。

パフォーマンス差が本当に効いてくる場面は2つあります:

1. コールドスタート(サーバーレス)

Prismaが歴史的に最も弱かった部分。Prisma 7で真正面から解決されました。

コールドスタート比較(AWS Lambda, Node.js 22):

Prisma 7.x(TypeScriptエンジン):
  - Rustバイナリの初期化不要
  - TS/WASMエンジンロード:~40-80ms
  - 初回クエリ:合計~80-150ms

Drizzle 0.45.x:
  - エンジン自体なし
  - コネクション確立:~20-50ms
  - 初回クエリ:合計~50-100ms

参考 — Prisma 5.x(旧Rustエンジン):
  - エンジン初期化:~500-1500ms
  - 初回クエリ:合計~600-1800ms

改善幅は劇的です。Prisma 7のコールドスタートはDrizzleと同じ水準になり、桁が違うということはもうありません。Drizzleがまだ勝ちますが、差は~50-80msであって、1秒ではありません。

2. バンドルサイズ

ここがDrizzle最大の強みです:

バンドルサイズ(ランタイム):

Prisma 7.x:
  @prisma/client + TSエンジン:~1.6MB(gzip 600KB)
  prisma(CLI):              ~15MB(開発時のみ)
  ランタイム合計:              ~1.6MB

Drizzle 0.45.x:
  drizzle-orm:    ~12KB
  drizzle-kit:    ~8MB(CLI、開発時のみ)
  ランタイム合計:  ~12KB

Prisma 7で大幅に縮小されたとはいえ、Drizzleのランタイムは依然として~130倍小さいです。これが効く場面:

  • Dockerイメージサイズ
  • サーバーレス関数のパッケージング(AWS Lambda 250MB制限)
  • エッジランタイムへのデプロイ(Cloudflare Workersの厳格なサイズ制限)
  • CI/CDパイプラインの速度

エッジランタイム対応

ここもPrisma 7で大きく状況が変わりました:

Drizzle: Cloudflare Workers、Vercel Edge Functions、Deno Deployなど、あらゆるエッジランタイムでネイティブ動作。バイナリ依存なし。最初からそうでした。

Prisma 7: Rustエンジンが廃止され、Driver Adapterがコアアーキテクチャの必須部品に格上げされました(もう実験的機能ではありません)。TypeScriptエンジンのおかげでエッジ環境でネイティブ動作し、基本的なエッジ対応にPrisma Accelerateプロキシは不要になりました。

かなり対等な競争になっています。極端にサイズが制限される環境(Cloudflare Workersでは12KBと1.6MBの差は効きます)ではDrizzleが有利ですが、Prismaがアーキテクチャ的にエッジから締め出される時代は終わりました。

マイグレーション

Prisma Migrate

Prismaのマイグレーションは成熟していて、明確な設計方針を持っています:

# schema.prismaを変更した後: npx prisma migrate dev --name add_user_avatar # これで自動的に: # 1. スキーマとDBの差分を比較 # 2. SQLマイグレーションファイルを生成 # 3. 開発DBに適用 # 4. Prisma Clientを再生成

開発体験は滑らかです。スキーマを変更して、コマンドを1つ叩くだけ。

Drizzle Kit

Drizzle Kitは別のワークフローを提供します:

# TypeScriptスキーマを変更した後: npx drizzle-kit generate --name add_user_avatar # 適用: npx drizzle-kit migrate

高速プロトタイピング用のpushモードもあります:

npx drizzle-kit push

実用上はどちらもうまく機能します。Prismaのほうがデータ損失検出やインタラクティブプロンプトの面で成熟しています。Drizzle Kitも(特に1.0に向けて)大きく進化しましたが、生成SQLが最適でないケースにたまに遭遇することがあります。

型安全性:掘り下げて比較

どちらもTypeScript統合は優秀ですが、実現アプローチが異なります。

Prismaの型生成

// Prismaが自動生成 type User = { id: number; email: string; name: string | null; createdAt: Date; updatedAt: Date; };

型は常にスキーマと同期しますが、prisma generateを実行した後にだけです。Prisma 7は型チェック速度も約70%改善しています。

Drizzleの型推論

type User = typeof users.$inferSelect; // Select型 type NewUser = typeof users.$inferInsert; // Insert型 // スキーマ変更と同時に型が更新される

DrizzleのスキーマはTypeScriptなので、ファイルを保存した瞬間に型が変わります。生成ステップ不要、古い型の心配なし、postinstallフックも不要です。

即時性ではDrizzleの勝ちです。 コードから直接推論されるので、常に最新の型が使えます。

一方で、生成されるヘルパー型ではPrismaが勝ります。 UserCreateNestedManyWithoutAuthorInputのような複雑なインプット型を自動で作ってくれるので、ネストしたリレーションの操作が楽です。Drizzleでは同じことを手動で組み立てる必要があります。

実践的な選び方ガイド

「どっちが優れているか?」ではなく、**「自分の制約にどちらが合うか?」**を問いましょう。

Prismaを選ぶべきケース:

  • チームのSQL経験にばらつきがある場合。 Prismaの抽象化が、経験の浅いメンバーをSQLの複雑さから守ってくれます。

  • 成熟したエコシステムが必要な場合。 Prismaは何千もの企業で何年もプロダクション利用されています。周辺ツールも充実しています。

  • 従来型サーバーでもサーバーレスでも。 Prisma 7のコールドスタート改善により、サーバーレスのペナルティはもうディールブレイカーではありません。Express、Fastify、NestJS、Lambda、どれでも大丈夫です。

  • 規約ベースの開発が好みの場合。 Prismaが多くの判断を代わりにしてくれるので、意思決定の負担が減ります。

Drizzleを選ぶべきケース:

  • サイズ制限の厳しいエッジにデプロイする場合。 12KBのランタイムはCloudflare Workers等で圧倒的です。Prisma 7の1.6MBもほとんどのエッジで動きますが、余裕の大きさが違います。

  • チームがSQLに強い場合。 SQLを書くのが得意なら、DrizzleのSQLファーストAPIは自然に感じるはずです。新しい抽象を覚えるのではなく、型安全なSQLを書くだけです。

  • コード生成を避けたい場合。 ビルドステップやpostinstallフック、生成ファイルが煩わしいなら、Drizzleの推論ベースのアプローチがすっきりします。

  • オーバーヘッドを極限まで減らしたい場合。 差は縮まりましたが、Drizzleのランタイムオーバーヘッドは依然として少ないです。

  • 複数データベースに対応したい場合。 DrizzleはPostgreSQL、MySQL、SQLite、Turso(LibSQL)を高品質にサポートしています。

ハイブリッドという選択肢

あまり語られないのですが、両方使うこともできます。同じプロジェクトで混在させるのではなく(それは混乱の元)、アーキテクチャ的に分ける方法です:

  • メインのアプリケーションサーバーには、エコシステムと生産性を活かせるPrisma
  • サイズ制約のあるエッジ関数やマイクロサービスには、12KBが武器になるDrizzle

2026年の多くのプロダクションアーキテクチャが、実際にこのパターンで運用しています。

比較記事が触れないこと:Prismaのビジネスモデル

比較記事がたいてい飛ばすテーマに触れておきましょう。持続可能性とビジネスモデルです。

Prismaはベンチャーキャピタルの支援を受けた企業です。無料のORMでユーザーを獲得し、有料サービス(Prisma Accelerate、Prisma Optimize、Prisma Postgres)で収益化しています。これ自体は悪いことではありませんが、Prismaのロードマップが商業的な優先事項の影響を受けるという点は認識しておくべきです。

Drizzle ORMはオープンソースで、Drizzle Teamが開発・運営しています。Drizzle Studioもリリースされ商用計画もありますが、ORMのコア機能は制限なしの完全オープンソースです。1.0に向けて進行中(現在v1.0.0-beta.15)で、プロジェクトは急速に成熟しています。

どちらのモデルがより「信頼できる」とは言い切れません。ただ、日々使うツールの背景にあるインセンティブ構造は把握しておきたいところです。

切り替えるなら

Prisma → Drizzle

移行手順は明確です:

  1. drizzle-kit introspectで既存DBからDrizzleスキーマを生成
  2. Prismaクエリをファイル単位で置き換え
  3. 移行期間中は両方のORMを並行運用
  4. すべて移行したらPrismaを削除

最も手間がかかるのは、Prismaのネストincludeやリレーションミューテーションを使った複雑なクエリの書き直しです。

Drizzle → Prisma

  1. prisma db pullでデータベースから.prismaスキーマを生成
  2. prisma generateでクライアントを作成
  3. DrizzleクエリをPrisma相当に書き換え
  4. Prismaの高レベルAPIはほとんどのクエリをより簡潔に表現できるため、移行は比較的スムーズです

今後の展望

両方のORMが急速に進化しており、最も面白いトレンドは収束です。

Prisma 7は分水嶺でした。RustエンジンからTypeScript/WASMへの移行で、最大のアーキテクチャ的弱点を解消。Driver Adapterが実験的な付け足しではなく、コアの必須コンポーネントへ。結果として、より軽く、より速く、格段にポータブルになりました。Prisma Postgres(マネージドDB)はORMと密に統合されており、プラットフォーム戦略は拡大を続けています。

Drizzleは1.0に向けて突き進んでおり、ベータ段階でvalidatorパッケージ(drizzle-zod、drizzle-valibot)のコア統合を進めています。開発体験の改善(エラーメッセージ、マイグレーション生成)とエコシステム拡大(Drizzle Studio、認証連携)に注力中です。

大きな流れとして、Prismaはより軽くSQL寄りに、Drizzleはより多機能で抽象化が洗練される方向へ。両者の差は、多くの開発者が思っているより速く縮まっています。

まとめ

率直に言います。どちらも優れた選択肢です。 2026年のTypeScript ORM環境は本当に充実していて、どちらを選んでも大きな失敗にはなりません。

あえて一文に凝縮するなら:

代わりに考えてくれるORMがほしいならPrisma。一緒に考えてくれるORMがほしいならDrizzle。

Prismaは複雑さを隠すのが得意。Drizzleは複雑さを型安全に扱うのが得意。選ぶ基準は、チームのSQL力、デプロイ先、そして抽象化に対する好みです。

確実に変わったことが一つあります。パフォーマンスはもう、どちらかの圧勝ではありません。 Prisma 7が、前世代を特徴づけていたコールドスタートの重さを解消しました。Drizzleは純粋な効率では依然リードしていますが、その差は秒やメガバイトではなく、ミリ秒やキロバイトの単位です。

Twitterのホットテイクに判断を委ねず、プロジェクトに合うものを選んで、いいものを作って、本当に大事な課題に向き合いましょう。

TypeScriptDrizzlePrismaORMNode.jsdatabasebackendPostgreSQL

関連ツールを見る

Pockitの無料開発者ツールを試してみましょう