karawaci.kode

2026-06-05 · 7 min

Drizzle vs Prisma di RSC 2026: 8 Bulan Production

Klien SaaS Jakarta saya (yang sama dengan Server Actions saya tulis kemarin) 8 bulan lalu protes: cold start function Vercel 2,8 detik. Penyebab utama: Prisma client bundle 6,2MB. Saya migrasi ke Drizzle. Ini ceritanya.

Setup

App: SaaS invoice + e-faktur, Next.js 15 App Router, Vercel Pro. Database: Postgres 17 di Neon (Singapore region). ORM lama: Prisma 5.x. ~38 model, ~120 relation.

Decision driver: cold start. Vercel charging untuk function execution time, dan cold start counts. Bundle besar = slow cold start.

Migration timeline

Minggu 1: Schema introspection dari Prisma ke Drizzle. Drizzle pakai drizzle-kit introspect yang generate schema TS dari Postgres existing. Hasilnya 80% accurate. Saya manual fix 20% untuk relation naming + enum.

// Drizzle schema example
export const invoices = pgTable('invoices', {
  id: uuid('id').primaryKey().defaultRandom(),
  tenantId: uuid('tenant_id').notNull().references(() => tenants.id),
  amount: numeric('amount', { precision: 18, scale: 2 }).notNull(),
  createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
});

Minggu 2: Rewrite query. Prisma query API dan Drizzle beda jauh. Prisma nested include, Drizzle pakai with + relational query atau explicit join. Saya rewrite ~140 query, kebanyakan straightforward.

Minggu 3: Test + parallel run. Saya jalankan dual-write (write ke Prisma + Drizzle simultan) selama 7 hari. Compare hasil row-by-row. Found 3 diff: timestamp timezone handling (Drizzle return Date, Prisma return Date dengan timezone offset string). Saya normalize di layer atas.

Total: ~85 jam engineering time. Tagihan ke klien: Rp 21jt.

Cold start

Sebelum (Prisma):

  • Bundle size /api/invoice/create: 6,8MB (Prisma client + query engine)
  • Cold start P50: 2,8 detik
  • Cold start P95: 4,2 detik

Sesudah (Drizzle):

  • Bundle size /api/invoice/create: 240KB (Drizzle + postgres.js driver)
  • Cold start P50: 1,0 detik
  • Cold start P95: 1,6 detik

Cold start turun 64%. Bundle turun 96%.

Untuk traffic yang scatter sepanjang hari (B2B invoice app, banyak idle period), cold start signifikan kena user experience. Klien dapat 3 customer feedback positive minggu pertama: “buka aplikasi lebih cepat”.

Latency steady-state (warm)

Steady-state query latency hampir sama (Prisma dan Drizzle keduanya thin layer di atas pg driver):

  • Simple select by ID: Prisma 8ms, Drizzle 7ms
  • Complex join 4 table: Prisma 22ms, Drizzle 19ms
  • Insert single row: Prisma 11ms, Drizzle 9ms

Beda real, tapi <10%. Tidak material untuk decision.

Yang break (2 incident)

Incident 1 (week 6 production): Drizzle query db.select().from(invoices).where(eq(invoices.tenantId, tenantId)) accidentally return semua row karena tenantId undefined (bug upstream di session). Prisma akan throw error untuk undefined comparison. Drizzle pass through, generate SQL WHERE tenant_id IS NULL lalu jadi WHERE NULL = NULL yang FALSE — TAPI saya pakai pattern or(eq(...), ...) di logic auth bypass, jadi bocor.

Real impact: 23 tenant lihat data tenant lain selama 4 jam sebelum klien notify saya. Hot fix: rollback function affected, add explicit assertTenantId() di tiap query, audit semua query untuk pattern serupa.

Damage: trust hit. Klien minta postmortem written. Pola sama dengan postmortem deploy Jumat saya — alat baru, edge case yang saya tidak antisipasi.

Incident 2 (week 9): Drizzle transaction default isolation level di postgres.js driver beda dari Prisma. Race condition di counter increment. Fix: explicit db.transaction(async tx => ..., { isolationLevel: 'serializable' }).

Total downtime: ~6 jam in 8 bulan. Mostly partial impact.

Memory

Vercel function RAM usage:

  • Prisma version: 220MB rata-rata, peak 410MB
  • Drizzle version: 95MB rata-rata, peak 180MB

Drizzle lebih ringan ~57%. Vercel memory pricing tidak terlalu sensitive, tapi consequence: bisa pakai function size lebih kecil ($/GB-s), saving ~$22/mo.

Cost

Vercel Pro saving (dari faster cold start + smaller bundle): ~$45/mo. Dalam 6 bulan: $270 saving.

Migration cost: Rp 21jt (engineering).

Break-even: ~5 bulan. Saat ini sudah 8 bulan production, net positive.

DX comparison

Prisma menang di:

  • Schema definition file (.prisma) lebih readable dari TypeScript schema Drizzle
  • Studio (GUI) sangat bagus untuk debug data
  • Ekosistem matang (lots of guides, Stack Overflow answer)
  • Error message lebih helpful untuk junior dev

Drizzle menang di:

  • Type-safety lebih tight (no as any escape hatch yang kadang Prisma butuh)
  • Bundle size + edge runtime compatibility
  • SQL-first API, easier untuk migrate kompleks query
  • No code generation step (instant feedback di IDE)

Verdict

Untuk Next.js 15 RSC dengan Vercel: Drizzle clear winner kalau cold start matters. Untuk Express / long-running Node server: Prisma masih oke, cold start irrelevant.

Bukan magic — migration 3 minggu + 2 incident bukan trivial cost. Hitung break-even sebelum commit. Untuk klien saya, hitung-an positif. Untuk project < 100 user atau traffic minim: tidak perlu migrate, optimize lain dulu.

Ditulis oleh Reza Pradipta