Prisma vs Drizzle ORM徹底比較 — 2026年どちらを選ぶべきか
TypeScriptエコシステムにおいて、Prisma と Drizzle ORM は最も人気のあるORMです。この記事では、両者の特徴を徹底比較し、プロジェクトに最適な選択をサポートします。
概要と哲学の違い
Prisma
- スキーマファースト: 独自のスキーマ言語(PSL)でデータモデルを定義
- 抽象化重視: SQLを隠蔽し、高レベルなAPIを提供
- ツールチェーン: Prisma Studio、マイグレーション、シード機能を統合
- 成熟度: 2019年リリース、大規模プロダクションでの実績多数
Drizzle ORM
- TypeScriptファースト: スキーマをTypeScriptで直接定義
- SQL親和性: 生SQLに近いクエリビルダー
- 軽量・高速: バンドルサイズが小さく、エッジランタイム対応
- 成熟度: 2022年リリース、急速に人気上昇中
スキーマ定義の比較
Prisma Schema Language
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(uuid())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
id String @id @default(uuid())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String
tags Tag[]
createdAt DateTime @default(now())
}
model Tag {
id String @id @default(uuid())
name String @unique
posts Post[]
}
利点:
- 直感的でわかりやすい
- リレーションが視覚的に明確
- IDEサポートが充実
欠点:
- 独自言語の学習コスト
- TypeScriptコードと分離
Drizzle Schema (TypeScript)
// schema.ts
import { pgTable, uuid, varchar, text, boolean, timestamp, pgEnum } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
email: varchar('email', { length: 255 }).notNull().unique(),
name: varchar('name', { length: 255 }),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
});
export const posts = pgTable('posts', {
id: uuid('id').primaryKey().defaultRandom(),
title: varchar('title', { length: 255 }).notNull(),
content: text('content'),
published: boolean('published').notNull().default(false),
authorId: uuid('author_id').notNull().references(() => users.id),
createdAt: timestamp('created_at').notNull().defaultNow(),
});
export const tags = pgTable('tags', {
id: uuid('id').primaryKey().defaultRandom(),
name: varchar('name', { length: 100 }).notNull().unique(),
});
// リレーション定義
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one, many }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
利点:
- TypeScriptネイティブ、追加言語不要
- 型安全性が高い
- コード内で完結
欠点:
- やや冗長
- 初見ではわかりにくい
クエリAPIの比較
Prisma: 高レベルな抽象化
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// 基本的なCRUD
const user = await prisma.user.create({
data: {
email: 'user@example.com',
name: 'John Doe',
},
});
// リレーションを含む取得
const userWithPosts = await prisma.user.findUnique({
where: { id: userId },
include: {
posts: {
where: { published: true },
orderBy: { createdAt: 'desc' },
take: 10,
},
},
});
// トランザクション
await prisma.$transaction([
prisma.user.update({ where: { id: 1 }, data: { name: 'Updated' } }),
prisma.post.create({ data: { title: 'New Post', authorId: 1 } }),
]);
// 集約クエリ
const stats = await prisma.post.aggregate({
_count: { id: true },
_avg: { viewCount: true },
where: { published: true },
});
// Raw SQL(エスケープ処理)
const result = await prisma.$queryRaw`
SELECT * FROM users WHERE email = ${email}
`;
Drizzle: SQL親和性の高いAPI
import { drizzle } from 'drizzle-orm/node-postgres';
import { eq, desc, and, count, avg } from 'drizzle-orm';
import { users, posts } from './schema';
const db = drizzle(pool);
// 基本的なCRUD
const user = await db.insert(users).values({
email: 'user@example.com',
name: 'John Doe',
}).returning();
// リレーションを含む取得
const userWithPosts = await db.query.users.findFirst({
where: eq(users.id, userId),
with: {
posts: {
where: eq(posts.published, true),
orderBy: desc(posts.createdAt),
limit: 10,
},
},
});
// トランザクション
await db.transaction(async (tx) => {
await tx.update(users).set({ name: 'Updated' }).where(eq(users.id, 1));
await tx.insert(posts).values({ title: 'New Post', authorId: 1 });
});
// 集約クエリ
const [stats] = await db
.select({
count: count(posts.id),
avgViews: avg(posts.viewCount),
})
.from(posts)
.where(eq(posts.published, true));
// Raw SQL
const result = await db.execute(sql`
SELECT * FROM users WHERE email = ${email}
`);
マイグレーション
Prisma Migrate
# 開発用マイグレーション生成
npx prisma migrate dev --name add_user_roles
# 本番適用
npx prisma migrate deploy
# リセット(開発環境のみ)
npx prisma migrate reset
特徴:
- スキーマからマイグレーションを自動生成
- マイグレーション履歴を自動管理
- ロールバックは手動編集が必要
Drizzle Kit
# マイグレーション生成
npx drizzle-kit generate:pg
# マイグレーション適用
npx drizzle-kit push:pg
# Studioでスキーマ確認
npx drizzle-kit studio
// drizzle.config.ts
import type { Config } from 'drizzle-kit';
export default {
schema: './src/schema.ts',
out: './drizzle/migrations',
driver: 'pg',
dbCredentials: {
connectionString: process.env.DATABASE_URL!,
},
} satisfies Config;
特徴:
- TypeScriptスキーマからSQL生成
- Push(直接適用)とGenerate(マイグレーションファイル生成)の両対応
- 柔軟なカスタマイズが可能
パフォーマンス比較
バンドルサイズ
| ORM | バンドルサイズ | 備考 |
|---|---|---|
| Prisma Client | ~500KB | クライアント生成が必要 |
| Drizzle ORM | ~50KB | 軽量で高速 |
クエリパフォーマンス
ベンチマーク結果(1000件のクエリ実行):
// Prisma
console.time('Prisma');
for (let i = 0; i < 1000; i++) {
await prisma.user.findMany({ take: 10 });
}
console.timeEnd('Prisma'); // ~2500ms
// Drizzle
console.time('Drizzle');
for (let i = 0; i < 1000; i++) {
await db.select().from(users).limit(10);
}
console.timeEnd('Drizzle'); // ~1800ms
Drizzleの方が約30%高速(環境により変動)。
エッジランタイム対応
Prisma
// Cloudflare Workers での制限
import { PrismaClient } from '@prisma/client/edge';
import { withAccelerate } from '@prisma/extension-accelerate';
const prisma = new PrismaClient().$extends(withAccelerate());
// Prisma Accelerate(有料サービス)が必要
Drizzle
// Cloudflare Workers でネイティブ対応
import { drizzle } from 'drizzle-orm/d1';
export default {
async fetch(request: Request, env: Env) {
const db = drizzle(env.DB);
const users = await db.select().from(usersTable);
return Response.json(users);
},
};
エッジ対応:
- Drizzleはエッジランタイムをネイティブサポート
- PrismaはAccelerate(有料)が必要
DX(開発者体験)
Prisma
利点:
- Prisma Studioでデータを視覚的に確認
- マイグレーション管理が簡単
- ドキュメントが充実
- エコシステムが成熟
欠点:
- 生成されたクライアントコードが大きい
- スキーマ変更後に再生成が必要
- カスタムクエリの自由度が低い
Drizzle
利点:
- TypeScriptコード内で完結
- SQLに近い柔軟性
- バンドルサイズが小さい
- エッジランタイム対応
欠点:
- ツールチェーンがまだ発展途上
- ドキュメントがPrismaほど充実していない
- 学習曲線がやや急
どちらを選ぶべきか
Prismaを選ぶべき場合
- フルスタックアプリケーション: Next.js, Remix等のサーバーレンダリング
- チーム開発: 統一されたスキーマ定義が重要
- データモデル重視: リレーションが複雑なアプリ
- 成熟したエコシステム: 安定性を優先
- Prisma Studioを活用: GUI管理ツールが欲しい
Drizzleを選ぶべき場合
- エッジデプロイ: Cloudflare Workers, Vercel Edge Functions
- パフォーマンス重視: バンドルサイズやクエリ速度が重要
- SQL親和性: 生SQLに近い柔軟性が欲しい
- TypeScriptネイティブ: スキーマもTypeScriptで管理したい
- 軽量アプリケーション: サーバーレス関数等
ハイブリッドアプローチ
// 複雑なクエリにはDrizzle、管理系にはPrisma
import { PrismaClient } from '@prisma/client';
import { drizzle } from 'drizzle-orm/node-postgres';
const prisma = new PrismaClient();
const db = drizzle(pool);
// 管理画面はPrisma
async function adminQuery() {
return prisma.user.findMany({ include: { posts: true } });
}
// パフォーマンス重視のAPIはDrizzle
async function fastQuery() {
return db.select().from(users).limit(100);
}
まとめ
| 項目 | Prisma | Drizzle |
|---|---|---|
| スキーマ定義 | PSL(独自言語) | TypeScript |
| バンドルサイズ | 大きい (~500KB) | 小さい (~50KB) |
| パフォーマンス | 良好 | 優秀 |
| エッジ対応 | 限定的(有料) | ネイティブ対応 |
| DX | 優秀 | 良好 |
| エコシステム | 成熟 | 発展中 |
| 学習曲線 | 緩やか | やや急 |
2026年の推奨:
- 新規プロジェクト: Drizzle ORM(特にエッジ環境)
- 既存Prismaプロジェクト: そのまま継続でOK
- 大規模チーム: Prismaの統一性が有利
- パフォーマンス最優先: Drizzle
どちらも優れたORMであり、プロジェクトの要件に応じて選択しましょう。Drizzleは急速に進化しており、2026年はさらに注目度が高まると予想されます。