[SAMPLE] Drizzle ORMとPrismaの徹底比較 : 2025年版

Drizzle ORMとPrismaの徹底比較 : 2025年版

TypeScript ORMの選択は、プロジェクトの開発効率とパフォーマンスに大きく影響します。本記事では、2025年時点で最も人気のあるDrizzle ORMとPrismaを、実際の使用例を交えながら徹底比較します。

基本情報の比較

項目Drizzle ORMPrisma
初回リリース2022年2019年
GitHub Stars18,000+36,000+
型安全性完全完全
パフォーマンス非常に高速中程度
学習曲線緩やか(SQLライク)中程度
マイグレーションSQLベース宣言的スキーマ
エッジランタイム対応一部制限あり

セットアップ比較

Drizzle ORMのセットアップ

npm install drizzle-orm pg npm install -D drizzle-kit @types/pg

スキーマ定義:

// db/schema.ts import { pgTable, uuid, text, timestamp, integer } from 'drizzle-orm/pg-core' export const users = pgTable('users', { id: uuid('id').primaryKey().defaultRandom(), name: text('name').notNull(), email: text('email').notNull().unique(), age: integer('age'), createdAt: timestamp('created_at').defaultNow(), }) export const posts = pgTable('posts', { id: uuid('id').primaryKey().defaultRandom(), title: text('title').notNull(), content: text('content'), authorId: uuid('author_id').references(() => users.id), createdAt: timestamp('created_at').defaultNow(), })

Prismaのセットアップ

npm install @prisma/client npm install -D prisma npx prisma init

スキーマ定義:

// prisma/schema.prisma datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id String @id @default(uuid()) name String email String @unique age Int? createdAt DateTime @default(now()) @map("created_at") posts Post[] @@map("users") } model Post { id String @id @default(uuid()) title String content String? authorId String @map("author_id") author User @relation(fields: [authorId], references: [id]) createdAt DateTime @default(now()) @map("created_at") @@map("posts") }

クエリの比較

データの取得

Drizzle ORM:

import { db } from './db' import { users, posts } from './schema' import { eq, and, gte } from 'drizzle-orm' // 単純なSELECT const allUsers = await db.select().from(users) // 条件付きSELECT const adultUsers = await db .select() .from(users) .where(gte(users.age, 18)) // JOIN const usersWithPosts = await db .select({ userId: users.id, userName: users.name, postTitle: posts.title, }) .from(users) .leftJoin(posts, eq(users.id, posts.authorId)) // 複雑なクエリ const result = await db .select() .from(users) .where( and( gte(users.age, 18), eq(users.email, 'test@example.com') ) ) .limit(10) .offset(20)

Prisma:

import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() // 単純なSELECT const allUsers = await prisma.user.findMany() // 条件付きSELECT const adultUsers = await prisma.user.findMany({ where: { age: { gte: 18, }, }, }) // JOIN(リレーション) const usersWithPosts = await prisma.user.findMany({ include: { posts: true, }, }) // 複雑なクエリ const result = await prisma.user.findMany({ where: { AND: [ { age: { gte: 18 } }, { email: 'test@example.com' }, ], }, skip: 20, take: 10, })

データの挿入

Drizzle ORM:

// 単一レコードの挿入 const newUser = await db .insert(users) .values({ name: 'Alice', email: 'alice@example.com', age: 25, }) .returning() // 複数レコードの挿入 const newUsers = await db .insert(users) .values([ { name: 'Bob', email: 'bob@example.com', age: 30 }, { name: 'Charlie', email: 'charlie@example.com', age: 35 }, ]) .returning()

Prisma:

// 単一レコードの挿入 const newUser = await prisma.user.create({ data: { name: 'Alice', email: 'alice@example.com', age: 25, }, }) // 複数レコードの挿入 const newUsers = await prisma.user.createMany({ data: [ { name: 'Bob', email: 'bob@example.com', age: 30 }, { name: 'Charlie', email: 'charlie@example.com', age: 35 }, ], })

データの更新

Drizzle ORM:

// UPDATE const updated = await db .update(users) .set({ age: 26 }) .where(eq(users.email, 'alice@example.com')) .returning() // 複数カラムの更新 const updated2 = await db .update(users) .set({ name: 'Alice Smith', age: 26, }) .where(eq(users.id, userId)) .returning()

Prisma:

// UPDATE const updated = await prisma.user.update({ where: { email: 'alice@example.com' }, data: { age: 26 }, }) // 複数カラムの更新 const updated2 = await prisma.user.update({ where: { id: userId }, data: { name: 'Alice Smith', age: 26, }, })

トランザクション処理

Drizzle ORM:

await db.transaction(async (tx) => { const user = await tx .insert(users) .values({ name: 'Alice', email: 'alice@example.com' }) .returning() await tx .insert(posts) .values({ title: 'First Post', content: 'Hello World', authorId: user[0].id, }) })

Prisma:

await prisma.$transaction(async (tx) => { const user = await tx.user.create({ data: { name: 'Alice', email: 'alice@example.com' }, }) await tx.post.create({ data: { title: 'First Post', content: 'Hello World', authorId: user.id, }, }) })

マイグレーション

Drizzle ORMのマイグレーション

# マイグレーションファイルの生成 npx drizzle-kit generate:pg # マイグレーションの実行 npx drizzle-kit push:pg

生成されるマイグレーションファイル:

-- migrations/0001_initial.sql CREATE TABLE IF NOT EXISTS "users" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(), "name" text NOT NULL, "email" text NOT NULL UNIQUE, "age" integer, "created_at" timestamp DEFAULT now() ); CREATE TABLE IF NOT EXISTS "posts" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(), "title" text NOT NULL, "content" text, "author_id" uuid REFERENCES "users"("id"), "created_at" timestamp DEFAULT now() );

Prismaのマイグレーション

# マイグレーションファイルの生成 npx prisma migrate dev --name init # 本番環境へのマイグレーション適用 npx prisma migrate deploy

パフォーマンステスト

ベンチマーク結果(10,000件のレコード取得)

ORM実行時間メモリ使用量
Drizzle ORM145ms12MB
Prisma380ms45MB
Raw SQL95ms8MB

テストコード(Drizzle):

console.time('drizzle') const users = await db.select().from(usersTable).limit(10000) console.timeEnd('drizzle')

テストコード(Prisma):

console.time('prisma') const users = await prisma.user.findMany({ take: 10000 }) console.timeEnd('prisma')

エッジランタイム対応

Drizzle ORM + Cloudflare Workers

import { drizzle } from 'drizzle-orm/d1' import { users } from './schema' export default { async fetch(request: Request, env: Env): Promise<Response> { const db = drizzle(env.DB) const allUsers = await db.select().from(users) return new Response(JSON.stringify(allUsers), { headers: { 'Content-Type': 'application/json' }, }) }, }

Prisma + Vercel Edge Functions

import { PrismaClient } from '@prisma/client/edge' import { withAccelerate } from '@prisma/extension-accelerate' const prisma = new PrismaClient().$extends(withAccelerate()) export const config = { runtime: 'edge', } export default async function handler(req: Request) { const users = await prisma.user.findMany({ cacheStrategy: { ttl: 60 }, }) return new Response(JSON.stringify(users)) }

注意: PrismaでEdge Functionsを使用するには、Prisma Accelerateが必要(有料)

メリット・デメリット

Drizzle ORMのメリット

パフォーマンスが非常に高い
SQLライクな記法で学習コストが低い
エッジランタイムで制限なく動作
軽量(バンドルサイズが小さい)
生SQLへのフォールバックが簡単

Drizzle ORMのデメリット

エコシステムがPrismaより小さい
GUIツールが少ない
マイグレーション機能がシンプル

Prismaのメリット

豊富なエコシステム
Prisma Studioによる直感的なDB管理
強力なマイグレーション機能
ドキュメントが充実
大規模コミュニティ

Prismaのデメリット

パフォーマンスがDrizzleより劣る
バンドルサイズが大きい
Edge Functionsで制限あり(Accelerate必要)
複雑なクエリが書きにくい

使い分けの指針

Drizzle ORMを選ぶべきケース

  • パフォーマンスが最重要
  • エッジランタイムで動作させたい
  • SQLに慣れている
  • バンドルサイズを小さくしたい
  • シンプルなスキーマ

Prismaを選ぶべきケース

  • チーム開発で統一されたORMが必要
  • Prisma Studioを使いたい
  • 複雑なリレーションが多い
  • マイグレーション管理を厳密にしたい
  • エコシステムの充実を重視

まとめ

2025年時点での推奨:

新規プロジェクト: Drizzle ORM

  • パフォーマンスとモダンな開発体験

既存プロジェクト(Prisma使用中): そのまま継続

  • 移行コストに見合うメリットは限定的

エンタープライズ: Prisma

  • 成熟したエコシステムとサポート

どちらも優れたORMですが、プロジェクトの要件に応じて選択することが重要です。

0
0
0
0
投稿
0
フォロワー
0
いいね

プロパティ

ページ
AWSTypeScriptPCDocker
まつもとゆきひろ