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.
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):
| ORM | Cold start (Vercel Node) | Cold start (Vercel Edge) | Cold start (CF Workers) |
|---|---|---|---|
| Drizzle | 280-450ms | 80-150ms | 30-80ms |
| Kysely | 260-420ms | 75-140ms | 25-70ms |
| Prisma | 580-980ms | N/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):
| ORM | Total render time | First byte | Stream complete |
|---|---|---|---|
| Drizzle (Vercel Edge) | 220ms | 90ms | 350ms |
| Kysely (Vercel Edge) | 200ms | 85ms | 320ms |
| Drizzle (Node serverless) | 450ms | 280ms | 680ms |
| Prisma (Node serverless) | 950ms | 720ms | 1450ms |
| Prisma (Edge dengan Driver Adapter beta) | 700ms | 480ms | 1100ms |
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
| Scenario | Recommended |
|---|---|
| New Next.js 15 RSC project | Drizzle |
| Edge deploy (CF Pages, Vercel Edge) | Drizzle atau Kysely |
| Migrate Pages Router → App Router | Keep current ORM (cost > benefit) |
| SQL-heavy report dashboard | Kysely |
| Multi-tenant SaaS dengan complex auth | Drizzle (RLS via raw SQL) atau Prisma |
| Interactive transaction heavy | Prisma (best DX) atau Drizzle (manual) |
| Bundle size critical | Drizzle atau Kysely |
| DX prioritized over performance | Prisma |
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