İçeriğe geç
Sedat Demir
Geri dön

Prisma ORM vs Drizzle ORM: TypeScript Veritabanı Araçlarının Kapsamlı Karşılaştırması

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:

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:


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:

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 reset

Prisma'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 push

Drizzle 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ı:

Drizzle'ın Güçlü Yanları:


6. Hangi Durumda Hangisini Seçmeli?

Prisma'yı Tercih Edin:

Drizzle'ı Tercih Edin:


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.


Share this post on:

Sonraki Yazı
Elysia.js ile End-to-End Tip Güvenliği: Full-Stack TypeScript'in Geleceği