← Semua picks

Stack Comparison Conditional

Drizzle vs Kysely vs Prisma di RSC 2026

Tiga ORM dilihat dari sisi React Server Component compatibility, streaming, dan Server Action ergonomi. Saya pakai ketiga di RSC production sejak 2024. Verdict yang nuanced.

17 Juni 2026 · 9 menit ·Use case: ORM untuk Next.js 15 App Router + RSC SMB Indonesia
DrizzleKyselyPrismaReact Server Component

TL;DR

  • Drizzle: Default safe untuk RSC. Cold start cepat, edge-compatible, bundle minimal.
  • Kysely: SQL-builder alternatif untuk SQL purist. Comparable Drizzle untuk edge.
  • Prisma: Mature DX, work di RSC tapi cold start berat. Best untuk Node.js server (not edge).
  • Verdict: Drizzle default untuk Next.js 15 RSC. Kysely untuk niche. Prisma stay jika legacy.

Konteks

Saya pakai ketiga ORM di context RSC sejak App Router rilis 2023:

  • Drizzle + RSC (6 project): SaaS dental, ecommerce klinik, AI legal, dashboard HR, admin warung scale, marketing site dengan dynamic content
  • Prisma + RSC (2 project): SaaS legacy migrate dari Pages Router (kept Prisma), MVP Next.js 14 → 15 transition
  • Kysely + RSC (1 project): internal tool SQL-heavy

Untuk perspective ORM general (non-RSC): Drizzle vs Prisma vs Kysely.

Pricing

Ketiga gratis. Cost = effort + infra impact.

Infra impact (RSC context)

Cold start serverless function (RSC fetch DB):

ORMCold start (Vercel Node)Cold start (Vercel Edge)Cold start (CF Workers)
Drizzle280-450ms80-150ms30-80ms
Kysely260-420ms75-140ms25-70ms
Prisma580-980msN/A (binary issue)N/A (binary issue)

Untuk RSC heavy (10+ DB call per page render): Drizzle 3-5x lebih cepat total render time.

RSC pattern dengan masing-masing ORM

Drizzle di RSC

// app/users/page.tsx
import { db } from '@/lib/db';
import { users, posts } from '@/lib/db/schema';
import { eq } from 'drizzle-orm';

export default async function UsersPage() {
  const allUsers = await db.query.users.findMany({
    with: { posts: true },
    orderBy: (users, { desc }) => [desc(users.createdAt)],
    limit: 20,
  });

  return (
    <div>
      {allUsers.map(u => (
        <UserCard key={u.id} user={u} postCount={u.posts.length} />
      ))}
    </div>
  );
}

Bundle Server Component: ~50KB (Drizzle + query code).

Kysely di RSC

// app/users/page.tsx
import { db } from '@/lib/db';

export default async function UsersPage() {
  const allUsers = await db
    .selectFrom('users')
    .leftJoin('posts', 'posts.user_id', 'users.id')
    .selectAll('users')
    .select(db.fn.count('posts.id').as('postCount'))
    .groupBy('users.id')
    .orderBy('users.created_at', 'desc')
    .limit(20)
    .execute();

  return (
    <div>
      {allUsers.map(u => (
        <UserCard key={u.id} user={u} postCount={Number(u.postCount)} />
      ))}
    </div>
  );
}

Bundle: ~45KB. SQL lebih explicit.

Prisma di RSC

// app/users/page.tsx
import { prisma } from '@/lib/db';

export default async function UsersPage() {
  const allUsers = await prisma.user.findMany({
    include: {
      _count: { select: { posts: true } }
    },
    orderBy: { createdAt: 'desc' },
    take: 20,
  });

  return (
    <div>
      {allUsers.map(u => (
        <UserCard key={u.id} user={u} postCount={u._count.posts} />
      ))}
    </div>
  );
}

Bundle Server Component build: ~1.5MB (Prisma client). Cold start signifikan.

Server Action workflow

Drizzle Server Action

// app/users/actions.ts
'use server';

import { db } from '@/lib/db';
import { users } from '@/lib/db/schema';
import { eq } from 'drizzle-orm';
import { revalidatePath } from 'next/cache';
import { z } from 'zod';

const updateSchema = z.object({
  id: z.string(),
  name: z.string().min(1),
});

export async function updateUser(formData: FormData) {
  const data = updateSchema.parse({
    id: formData.get('id'),
    name: formData.get('name'),
  });

  await db.update(users).set({ name: data.name }).where(eq(users.id, data.id));
  revalidatePath('/users');
}

Prisma Server Action

'use server';

import { prisma } from '@/lib/db';
import { revalidatePath } from 'next/cache';
import { z } from 'zod';

const updateSchema = z.object({
  id: z.string(),
  name: z.string().min(1),
});

export async function updateUser(formData: FormData) {
  const data = updateSchema.parse({
    id: formData.get('id'),
    name: formData.get('name'),
  });

  await prisma.user.update({ where: { id: data.id }, data: { name: data.name } });
  revalidatePath('/users');
}

Syntax similar. Bundle output beda significantly.

Streaming + Suspense pattern

RSC enable streaming. Query DB di parallel via Suspense boundary:

Drizzle parallel fetch

export default function DashboardPage() {
  return (
    <div>
      <Suspense fallback={<UserListSkeleton />}>
        <UserList />
      </Suspense>
      <Suspense fallback={<RevenueChartSkeleton />}>
        <RevenueChart />
      </Suspense>
      <Suspense fallback={<RecentOrdersSkeleton />}>
        <RecentOrders />
      </Suspense>
    </div>
  );
}

async function UserList() {
  const users = await db.select().from(usersTable).limit(10);
  return <ul>{users.map(...)}</ul>;
}

async function RevenueChart() {
  const data = await db.execute(sql`SELECT ...`);
  return <Chart data={data} />;
}

Drizzle excel di pattern ini karena cold start cepat — 3 parallel query tidak bottleneck function init.

Prisma di pattern sama: cold start 1 function = 580-980ms × 3 parallel = total 1.7-3s. Drizzle 3 parallel = total 280-450ms.

Performance benchmark (production data)

Page dashboard dengan 8 DB query (mixed simple + complex):

ORMTotal render timeFirst byteStream complete
Drizzle (Vercel Edge)220ms90ms350ms
Kysely (Vercel Edge)200ms85ms320ms
Drizzle (Node serverless)450ms280ms680ms
Prisma (Node serverless)950ms720ms1450ms
Prisma (Edge dengan Driver Adapter beta)700ms480ms1100ms

Drizzle/Kysely di edge 4-7x lebih cepat dari Prisma di Node.

Trade-off untuk RSC

Drizzle untuk RSC

Pro: Cold start cepat — RSC dengan multiple DB call efficient. Bundle minimal — Server Component compile output kecil. Edge-compatible — bisa deploy ke CF Pages/Workers/Vercel Edge untuk latency Indonesia. Relational query API ergonomic. Type inference excellent.

Con: Relational deep nested kadang verbose dibanding Prisma include. Tidak ada built-in interactive transaction (workaround dengan db.transaction(async (tx) => ...)).

Kysely untuk RSC

Pro: Comparable Drizzle untuk edge. SQL builder paling thin abstraction. Cocok untuk SQL purist.

Con: No relational query API magic (manual join). Tidak ada Prisma Studio equivalent (lebih external tooling). Community lebih kecil.

Prisma untuk RSC

Pro: DX paling polished — generated client, type safety strict, Prisma Studio GUI. Interactive transaction API mature. Relational include() ergonomic untuk nested data.

Con: Cold start 300-800ms hit RSC pattern hard. Bundle 1.5MB client = build time + memory. Edge runtime butuh Driver Adapter (beta, fragile). Codegen step extra di workflow.

Konteks Indonesia

SaaS dental Jakarta (Drizzle + RSC + Edge): deploy Vercel Edge. 8 query per dashboard page render. Total render time 280ms median. Customer Indonesia feel “instant”.

Ecommerce klinik (Drizzle + RSC + CF Pages): deploy CF Pages Functions. Latency Jakarta 18ms TTFB. Stream rendering smooth.

SaaS legacy migrate (Prisma + RSC + Node): project 2023 Pages Router → 2024 App Router. Stay Prisma karena migration cost > benefit. Cold start hit — ditambah Vercel function warmup strategy.

Internal tool warung (Kysely + RSC + Node): SQL-heavy report query. Kysely fit karena kompleks query lebih clear di SQL syntax.

Use case decision matrix

ScenarioRecommended
New Next.js 15 RSC projectDrizzle
Edge deploy (CF Pages, Vercel Edge)Drizzle atau Kysely
Migrate Pages Router → App RouterKeep current ORM (cost > benefit)
SQL-heavy report dashboardKysely
Multi-tenant SaaS dengan complex authDrizzle (RLS via raw SQL) atau Prisma
Interactive transaction heavyPrisma (best DX) atau Drizzle (manual)
Bundle size criticalDrizzle atau Kysely
DX prioritized over performancePrisma

Migration paths (RSC context)

Prisma → Drizzle (RSC migration)

Effort: 90-180 menit untuk schema 15-30 table. Detail guide. Selain ORM migration, RSC pattern tidak banyak berubah — query Server Component sintaks similar.

Drizzle → Kysely

Effort: 4-8 jam. Schema definition similar TS-first. Query refactor: Drizzle relational API → manual join Kysely.

Yang surprising

Drizzle stream rendering smoother dari ekspektasi. Multiple parallel query di Suspense boundary feel native. RSC + Drizzle = pattern yang akhirnya tepat untuk SaaS dashboard.

Prisma di Edge masih shaky di 2026. Driver Adapter rilis stable Q4 2025, tapi beberapa edge case bug. Saya tidak rekomen Prisma + Edge untuk production critical sampai mid-2026.

Verdict

Conditional Recommend untuk ketiga:

Pakai Drizzle untuk RSC jika:

  • New Next.js 15 App Router project
  • Deploy edge (CF Pages, Vercel Edge)
  • Cold start sensitive
  • Default safe untuk SMB Indonesia

Pakai Kysely untuk RSC jika:

  • SQL purist atau SQL-heavy report
  • Comfort dengan ekosistem lebih kecil
  • Bundle size paling priority

Pakai Prisma untuk RSC jika:

  • Legacy project migrate dari Pages Router
  • Deploy Node serverless (bukan edge)
  • DX Prisma Studio + introspection critical
  • Tim familiar Prisma + reluctant migrate

Untuk migration concrete: Migrasi Prisma → Drizzle 90 Menit. Untuk ORM comparison umum: Drizzle vs Prisma vs Kysely.

Ditulis oleh Asti Larasati

// Pick Stack Comparison lain


← Semua picks RSS feed