Prisma 7 ve PostgreSQL: Üretim Kalitesinde Veri Katmanı
Bu rehberde ne öğreneceksiniz?
Bu yazı bir haber özeti değil; adım adım uygulayabileceğiniz bir öğretici makale (tutorial) formatındadır. Her bölümün sonunda pratik çıkarımlar ve üretim ortamında karşılaşacağınız senaryolar yer alır.
- İlişkisel şemayı okuma pattern'lerine göre tasarlamak
- Migration ve seed sürecini güvenli otomatikleştirmek
- N+1 problemini tespit edip çözmek
- Transaction ve soft delete ile tutarlı veri yönetmek
Ön koşullar
Rehberi verimli takip etmek için aşağıdaki bilgilere aşina olmanız önerilir. Eksik hissettiğiniz konularda ilgili bölümde ek kaynak ipuçları bulacaksınız.
- SQL temelleri (SELECT, JOIN, index kavramı)
- Docker ile local PostgreSQL veya managed DB erişimi
- TypeScript ve async/await
Güncellik ve teknoloji yığını
Makale 2026 itibarıyla güncellenmiştir. Örnekler ve API referansları şu yığınla uyumludur: Prisma 7.8+, PostgreSQL 16+, PrismaPg adapter, Node.js 22. Eski sürüm dokümantasyonu ile karıştırmamak için major versiyon farklarını özellikle belirttik.
Framework sürümleri hızla değişir; kalıcı olan prensipler (güvenlik, katman ayrımı, ölçüm) bu rehberin omurgasını oluşturur.
Bölüm 1: Şema tasarımı ve ilişkiler
Model çizmeden önce sorguları listeleyin: liste sayfası, detay, admin paneli, arama. Her ekran farklı include ihtiyacı doğurur.
Many-to-many için implicit join tablosu Prisma'da tags Tag[] ile temsil edilir. Self-relation (comment reply) için @relation("ReplyToComment") adlandırması şarttır.
UUID (@db.Uuid) dağıtık sistemlerde güvenlidir; sıralı ID isteyen raporlar için createdAt index'i ekleyin.
Adım adım uygulama
Aşağıdaki sırayı takip edin. Her adımı tamamlamadan bir sonrakine geçmeyin; özellikle güvenlik ve veri katmanı adımları atlanmamalıdır.
schema.prismadosyasında modelleri ve index'leri tanımlayın.npx prisma migrate dev --name init_blogile migration üretin.- Staging'de asla
db pushile migration atlamayın; drift oluşur.
model Blog {
id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
title String
published Boolean @default(false)
deletedAt DateTime? @db.Timestamptz(3)
tags Tag[]
@@index([published, createdAt])
}
Bölüm 2: Veri erişim katmanı
Route dosyalarında ham Prisma çağrısı kısa vadede hızlı, uzun vadede test edilemez yapı üretir. lib/data/ katmanı standarttır.
Adım adım uygulama
Aşağıdaki sırayı takip edin. Her adımı tamamlamadan bir sonrakine geçmeyin; özellikle güvenlik ve veri katmanı adımları atlanmamalıdır.
getPublishedBlogs(filters)tek sorumluluklu fonksiyon yazın.- Filtreleri tip güvenli
BlogFiltersobjesi ile alın. - Soft delete için her public sorguda
deletedAt: nullşartını unutmayın.
export async function getPublishedBlogs(filters: BlogFilters) {
return prisma.blog.findMany({
where: {
published: true,
deletedAt: null,
...(filters.tag && { tags: { some: { name: filters.tag } } }),
},
include: { tags: true, author: { select: { name: true, image: true } } },
orderBy: { createdAt: 'desc' },
take: filters.limit ?? 20,
});
}
Bölüm 3: N+1 ve performans
Liste sayfasında 20 blog + her biri için ayrı tag sorgusu = 21 round-trip. Prisma query log ile development'ta bunu görün.
include ile eager load birincil çözümdür. Çok büyük listelerde cursor pagination ve selective select kullanın.
- Development:
log: ["query", "warn"] - Production: yavaş sorgu eşiği ve structured log
- EXPLAIN ANALYZE ile DB tarafını doğrulayın
İpucu: Prisma 7 driver adapter (@prisma/adapter-pg) serverless ve long-running Node için pool ayarını dokümante edin.
Bölüm 4: Transaction ve seed
Blog oluşturma + taxonomy sync tek transaction içinde olmalı. Yarım yazılmış kayıt kullanıcıya asla görünmemeli.
Adım adım uygulama
Aşağıdaki sırayı takip edin. Her adımı tamamlamadan bir sonrakine geçmeyin; özellikle güvenlik ve veri katmanı adımları atlanmamalıdır.
- Seed script'lerini idempotent yazın (başlık veya slug ile kontrol).
- Seed içeriğini güncellediğinizde upsert veya update stratejisi belirleyin.
- Production credential'larını seed'e koymayın.
await prisma.$transaction(async (tx) => {
const blog = await tx.blog.create({ data: blogData });
await syncTaxonomyWithClient(tx, blog.id, tags, categories);
});
Bölüm 5: Read replica ve okuma/yazma ayrımı
Yüksek okuma trafiğinde primary'e rapor sorguları bindirmeyin.
Prisma ile birden fazla datasource veya middleware ile read replica yönlendirmesi yapılabilir. Tutarlılık gerektiren okumalar primary'de kalmalı.
// Örnek: ağır liste sorgusu replica'ya (pseudo)
const blogs = await prisma.$queryRaw`
SELECT id, title FROM "Blog" ORDER BY "createdAt" DESC LIMIT 20
`;
Bölüm 6: Yedekleme ve felaket kurtarma
Migration doğru olsa bile yedeksiz PostgreSQL production riskidir.
Production ortamında Prisma/PostgreSQL ile ilgili en sık görülen sorun, geliştirme ortamındaki varsayımların (küçük veri seti, tek kullanıcı, sıcak cache) canlı trafikte çökmemesidir. Bu yüzden her değişiklikten önce yük testi veya en azından p95 latency ölçümü yapın.
Structured logging (request id, route, süre, kullanıcı id’si — PII olmadan) ve hata oranı alarmları, sorunları kullanıcı şikayetinden önce yakalamanızı sağlar. Log’da stack trace tutun; kullanıcıya generic mesaj gösterin.
Dokümantasyonu kod ile birlikte güncelleyin: README, ADR (Architecture Decision Record) veya ekip wiki’sinde “neden bu kararı aldık?” sorusunun cevabı gelecekteki sizin en büyük yardımcınızdır.
- Günlük otomatik snapshot + PITR
- Restore drill'i çeyrekte bir kez
- Seed verisini production şemasından ayırın
Sık yapılan hatalar
Aşağıdaki tuzaklar eğitim ortamlarında nadiren, production'da ise pahalıya mal olur. Code review checklist'inize eklemenizi öneririz.
- Migration yerine sürekli db push kullanmak
- Public API'de soft-deleted kayıtları döndürmek
- Sınırsız connection açmak (PgBouncer olmadan scale)
- Index eklemeden milyon satırlı tabloda filtrelemek
Pratik alıştırmalar
Okumak yeterli değildir; öğrenmeyi pekiştirmek için küçük bir side-project veya mevcut kod tabanınızda şu görevleri uygulayın:
- Blog listesine kategori filtresi ekleyin ve explain ile sorguyu doğrulayın
- Yorum + reply oluşturmayı transaction ile sarın
- Seed'i iki kez çalıştırın; duplicate oluşmadığını kontrol edin
Özet ve sonraki adımlar
Bu rehberdeki prensipleri tek seferde tüm projeye uygulamaya çalışmayın. Önce tek bir route veya modül seçin, ölçün, sonra yaygınlaştırın.
- Read replica veya connection pool (PgBouncer) dokümantasyonunu okuyun
- PostgreSQL performans öğreticisine geçin
- Prisma Accelerate veya cache katmanını değerlendirin