Prisma ORM vs Drizzle ORM: TypeScript Veritabanı Araçlarının Kapsamlı Karşılaştırması
TypeScript ile backend geliştirme yapıyorsanız, veritabanı ile etkileşim kurmak için bir ORM seçmek projenizin temel kararlarından biridir. Uzun yıllar boyunca bu alanda Prisma neredeyse tartışmasız liderdi. Ancak 2023'ten itibaren sahneye çıkan Drizzle ORM, "SQL'i bilen geliştiriciler için ORM" sloganıyla ciddi bir alternatif haline geldi.
Bu yazıda her iki aracı derinlemesine karşılaştırarak, projeniz için en doğru kararı vermenize yardımcı olacağız.
Prisma ORM Nedir?
Prisma, Node.js ve TypeScript ekosisteminde en yaygın kullanılan ORM'lerden biridir. Kendi şema tanımlama dili (Prisma Schema Language) üzerinden veritabanı modellerinizi tanımlar ve bu şemadan otomatik olarak tam tip güvenlikli bir client oluşturur.
Temel Özellikleri:
- Deklaratif şema tanımlama (
.prismadosyası) - Otomatik migration sistemi
- Prisma Studio ile görsel veritabanı yönetimi
- Güçlü tip çıkarımı (type inference)
- PostgreSQL, MySQL, SQLite, MongoDB, CockroachDB desteği
Drizzle ORM Nedir?
Drizzle ORM, "headless" bir TypeScript ORM'idir. SQL'e yakın bir API sunarak geliştiricilerin SQL bilgisini doğrudan kullanabilmesini sağlar. Sıfır bağımlılık (zero dependencies) felsefesiyle öne çıkar ve hem serverless hem de edge runtime ortamlarında son derece performanslı çalışır.
Temel Özellikleri:
- TypeScript-first şema tanımlama
- SQL-like sorgu API'si
- Sıfır bağımlılık, minimal bundle size
- Serverless ve edge-ready mimari
- PostgreSQL, MySQL, SQLite, Turso, Neon, PlanetScale desteği
1. Şema Tanımlama Yaklaşımları
İki ORM arasındaki en belirgin fark, veritabanı şemasını nasıl tanımladığınızdır.
Prisma Şema Tanımlama
Prisma, kendi özel DSL'ini (Domain Specific Language) kullanır:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
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
createdAt DateTime @default(now())
}Drizzle Şema Tanımlama
Drizzle, doğrudan TypeScript dosyalarında şema tanımlar:
// src/db/schema.ts
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').unique().notNull(),
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 usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));Önemli fark: Prisma'nın DSL'i öğrenmesi kolaydır ancak TypeScript ekosistemi dışında kalır. Drizzle'ın yaklaşımı ise tamamen TypeScript içindedir; bu sayede IDE desteği, refactoring ve tip kontrolü doğal olarak çalışır.
2. Sorgu API'leri Karşılaştırması
Prisma Sorgu API'si
Prisma, soyutlanmış ve nesne-tabanlı bir API sunar:
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// Basit sorgular
const allUsers = await prisma.user.findMany();
const userWithPosts = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true },
});
// Filtreleme ve sıralama
const publishedPosts = await prisma.post.findMany({
where: {
published: true,
author: {
email: { contains: '@example.com' },
},
},
orderBy: { createdAt: 'desc' },
take: 10,
skip: 0,
});
// Oluşturma
const newUser = await prisma.user.create({
data: {
email: 'ali@example.com',
name: 'Ali',
posts: {
create: [
{ title: 'İlk yazım', content: 'Merhaba dünya!' },
],
},
},
include: { posts: true },
});
// Transaction
const [updatedPost, newComment] = await prisma.$transaction([
prisma.post.update({
where: { id: 1 },
data: { published: true },
}),
prisma.comment.create({
data: { text: 'Harika yazı!', postId: 1 },
}),
]);Drizzle Sorgu API'si
Drizzle iki farklı API sunar: SQL-like API ve Relational Queries API.
import { drizzle } from 'drizzle-orm/node-postgres';
import { eq, and, like, desc } from 'drizzle-orm';
import * as schema from './schema';
const db = drizzle(pool, { schema });
// SQL-like API — SQL bilen geliştiriciler için doğal
const allUsers = await db.select().from(schema.users);
const publishedPosts = await db
.select()
.from(schema.posts)
.where(
and(
eq(schema.posts.published, true),
like(schema.users.email, '%@example.com%')
)
)
.leftJoin(schema.users, eq(schema.posts.authorId, schema.users.id))
.orderBy(desc(schema.posts.createdAt))
.limit(10)
.offset(0);
// Relational Queries API — Prisma benzeri
const userWithPosts = await db.query.users.findFirst({
where: eq(schema.users.id, 1),
with: {
posts: true,
},
});
// Oluşturma
const [newUser] = await db
.insert(schema.users)
.values({
email: 'ali@example.com',
name: 'Ali',
})
.returning();
// Transaction
await db.transaction(async (tx) => {
await tx
.update(schema.posts)
.set({ published: true })
.where(eq(schema.posts.id, 1));
await tx.insert(schema.comments).values({
text: 'Harika yazı!',
postId: 1,
});
});Drizzle'ın SQL-like API'si, oluşturulan SQL sorgusunu neredeyse birebir yansıtır. Bu sayede hangi SQL'in çalıştığını tahmin etmek çok kolaydır. Prisma'da ise bazen arkada hangi sorguların oluşturulduğunu anlamak için loglama yapmanız gerekebilir.
3. Performans Karşılaştırması
Performans, bu iki ORM arasındaki en tartışmalı konulardan biridir.
| Metrik | Prisma | Drizzle |
|---|---|---|
| Cold start süresi | Yavaş (Rust engine yüklemesi) | Çok hızlı (saf JS/TS) |
| Sorgu çalıştırma | Orta (Rust engine üzerinden) | Hızlı (doğrudan SQL driver) |
| Bundle boyutu | Büyük (~10MB+, engine dahil) | Minimal (~50KB) |
| Serverless uyumluluğu | Sınırlı (Prisma Accelerate gerekebilir) | Mükemmel |
| Edge runtime | Prisma Accelerate ile | Native destek |
| Bellek kullanımı | Yüksek | Düşük |
Neden bu fark var?
Prisma, sorguları Rust ile yazılmış bir Query Engine üzerinden çalıştırır. Bu engine, Prisma şemasını okur, sorguları optimize eder ve veritabanına gönderir. Bu yaklaşım güçlü optimizasyonlar sağlasa da:
- İlk başlatma süresi (cold start) uzar
- Bundle boyutu büyür
- Serverless ortamlarda ek maliyet oluşturur
Drizzle ise doğrudan veritabanı driver'ını kullanır — arada ek bir katman yoktur. Bu nedenle özellikle Vercel Edge Functions, Cloudflare Workers ve AWS Lambda gibi ortamlarda Drizzle belirgin şekilde avantajlıdır.
4. Migration Sistemi
Prisma Migrations
# Şema değişikliğinden sonra migration oluştur
npx prisma migrate dev --name add_user_role
# Production'da migration uygula
npx prisma migrate deploy
# Veritabanını sıfırla
npx prisma migrate resetPrisma'nın migration sistemi olgun ve güvenilirdir. Migration dosyaları SQL formatında oluşturulur ve versiyon kontrolüyle takip edilir.
Drizzle Migrations
# Migration oluştur
npx drizzle-kit generate
# Migration uygula
npx drizzle-kit migrate
# Şemayı doğrudan veritabanına push et (geliştirme)
npx drizzle-kit pushDrizzle Kit de benzer bir iş akışı sunar. drizzle.config.ts dosyasıyla konfigürasyon yapılır:
// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});Her iki migration sistemi de production-ready seviyededir, ancak Prisma'nın migration sistemi daha uzun süredir kullanıldığı için daha olgun kabul edilir.
5. Geliştirici Deneyimi (DX)
Prisma'nın Güçlü Yanları:
- Prisma Studio: Tarayıcı tabanlı görsel veritabanı arayüzü
- Kapsamlı dokümantasyon: Yıllardır gelişen, detaylı kaynaklar
- Büyük topluluk: Stack Overflow, Discord ve GitHub'da geniş destek
- VS Code eklentisi: Prisma şema dosyaları için söz dizimi vurgulama ve otomatik tamamlama
- Kolay öğrenme eğrisi: SQL bilgisi gerektirmez
Drizzle'ın Güçlü Yanları:
- Drizzle Studio: Web tabanlı veritabanı görüntüleyici
- SQL bilgisi transferi: SQL bilen biri hemen adapte olur
- Tam TypeScript entegrasyonu: Şema, sorgu, migration — her şey TypeScript
- Daha az "sihir": Oluşturulan SQL tahmin edilebilir
- Hızlı büyüyen topluluk: GitHub yıldız sayısı hızla artıyor
6. Hangi Durumda Hangisini Seçmeli?
Prisma'yı Tercih Edin:
- Hızlı prototipleme yapıyorsanız
- Ekibiniz SQL'e aşina değilse
- MongoDB desteğine ihtiyacınız varsa
- Olgun bir ekosistem ve geniş topluluk desteği istiyorsanız
- Prisma Studio ile görsel veritabanı yönetimi önemliyse
- Büyük bir ekipte standart bir yaklaşım gerekiyorsa
Drizzle'ı Tercih Edin:
- Serverless veya edge ortamda çalışıyorsanız
- Performans kritik bir uygulamanız varsa
- Ekibiniz SQL'e hakimse
- Minimal bundle boyutu önemliyse (Cloudflare Workers vb.)
- Oluşturulan SQL üzerinde tam kontrol istiyorsanız
- Turso, Neon, PlanetScale gibi modern veritabanlarını kullanıyorsanız
- Her şeyin TypeScript içinde kalmasını istiyorsanız
7. Gerçek Dünya Senaryosu: Next.js API Route
Her iki ORM'in de bir Next.js App Router API route'unda nasıl göründüğünü inceleyelim:
Prisma ile:
// app/api/users/route.ts
import { prisma } from '@/lib/prisma';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get('page') || '1');
const limit = 10;
const [users, total] = await Promise.all([
prisma.user.findMany({
skip: (page - 1) * limit,
take: limit,
include: {
posts: {
where: { published: true },
select: { id: true, title: true },
},
},
orderBy: { createdAt: 'desc' },
}),
prisma.user.count(),
]);
return NextResponse.json({ users, total, page });
}Drizzle ile:
// app/api/users/route.ts
import { db } from '@/lib/db';
import { users, posts } from '@/db/schema';
import { eq, desc, sql } from 'drizzle-orm';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get('page') || '1');
const limit = 10;
const [userList, countResult] = await Promise.all([
db.query.users.findMany({
limit,
offset: (page - 1) * limit,
orderBy: [desc(users.createdAt)],
with: {
posts: {
where: eq(posts.published, true),
columns: { id: true, title: true },
},
},
}),
db.select({ count: sql<number>`count(*)` }).from(users),
]);
return NextResponse.json({
users: userList,
total: countResult[0].count,
page,
});
}Gördüğünüz gibi, her iki yaklaşım da temiz ve okunabilir kod üretir. Tercih büyük ölçüde ekibinizin alışkanlıklarına ve projenizin gereksinimlerine bağlıdır.
Özet ve Sonuç
Prisma ve Drizzle, TypeScript ekosisteminin iki güçlü veritabanı aracıdır ve her ikisi de production-ready seviyededir. Aralarındaki seçim, projenizin doğasına ve ekibinizin tercihlerine göre şekillenmelidir.
Prisma, veritabanı karmaşıklığını soyutlayan, öğrenmesi kolay ve olgun bir ekosistem sunar. Hızlı başlamak isteyen ekipler ve SQL'e aşina olmayan geliştiriciler için mükemmel bir seçimdir.
Drizzle, SQL'e yakın yapısı, minimal boyutu ve üstün performansıyla öne çıkar. Serverless ortamlar, edge computing ve performans-kritik uygulamalar için güçlü bir tercihtir.
Son olarak şunu belirtmek gerekir: yanlış bir seçim yoktur. Her iki araç da aktif olarak geliştirilmekte, topluluğu büyümekte ve TypeScript ile veritabanı etkileşimini güvenli ve keyifli hale getirmektedir. Küçük bir proof-of-concept projesiyle ikisini de denemenizi ve ekibinize en uygun olanı seçmenizi öneririm.