Drizzle ORM × Next.js Serverless Guide — Practical Prisma Replacement
Drizzle ORM bundle ~50KB, Edge runtime support out of the box, Neon/Supabase/Turso integration. A hands-on guide to replacing Prisma in Next.js App Router + serverless environments as of April 2026.
On this page (12)
- Why Drizzle — Why Prisma Is Slow in Serverless
- Basic Setup with Next.js + Neon
- Schema Definition — Declaring Tables in TypeScript
- Type-Safe Query Writing
- Migration — drizzle-kit Workflow
- Supported DBs — Neon, Supabase, Turso, libSQL
- Drizzle vs Prisma — Full Comparison
- Use Case Recommendations — What to Use and When
- Real-World Pattern — Reading Data in Server Components
- 3 Common Sticking Points
- FAQ
- Wrapping Up
April 2026 · Developer Tools
For Next.js App Router and Vercel serverless, the ORM default is tilting fast toward Drizzle. ~50KB bundle (gzip ~7KB), Edge runtime support out of the box, and official integrations with Neon, Supabase, and Turso — a design tuned for serverless. Prisma 7 dropped its Rust engine and shrank its bundle by ~90%, but Drizzle is still an order of magnitude lighter.
This post is a focused guide for taking Drizzle into a real Next.js project. Setup, schema definition, type-safe queries, migration workflow, and Server Component patterns — all in working code. Neon is the default DB here, with notes on Supabase and Turso differences where relevant.
Bottom line: for solo and small-team serverless projects, Drizzle + Neon is close to the optimal default. For larger teams where Prisma Studio's GUI matters, Prisma still holds up. Neither is universally better — the answer depends on stack and team size.
- Drizzle ORM bundle ~50KB (gzip ~7KB) vs Prisma 7 ~1.6MB — tangible cold start gap
- Edge runtime works by default — Vercel Edge Functions and Cloudflare Workers without extra config
- Schema is a single TypeScript file — drizzle-kit auto-generates SQL diffs
- Types auto-inferred — $inferSelect and $inferInsert reusable as API types
- Supported DBs — PostgreSQL (Neon, Supabase), SQLite (Turso, libSQL), MySQL (PlanetScale)
- drizzle-kit push is for local testing; migrate is for production — don't mix them
- Import db directly in Next.js Server Components — no state management needed
- Why Drizzle — Why Prisma Is Slow in Serverless
- Basic Setup with Next.js + Neon
- Schema Definition — Declaring Tables in TypeScript
- Type-Safe Query Writing
- Migration — drizzle-kit Workflow
- Supported DBs — Neon, Supabase, Turso, libSQL
- Drizzle vs Prisma — Full Comparison
- Real-World Pattern — Reading Data in Server Components
- 3 Common Sticking Points
- FAQ
Why Drizzle — Why Prisma Is Slow in Serverless
Prisma 7's bundle size is around 1.6MB. This directly impacts serverless cold starts. Drizzle comes in at ~50KB (gzip ~7KB) — the difference is noticeable. Prisma 7 dropped the Rust engine to cut ~90%, but Drizzle remains an order of magnitude lighter.
A cold start is the time it takes to load code when a serverless function runs for the first time. Think of it like a computer booting up its OS. The bigger the bundle, the longer the wait. For services that go from zero traffic to a sudden spike, this hits UX directly.
In Edge runtime, Prisma requires a separate adapter. Drizzle works out of the box. Both Vercel Edge Functions and Cloudflare Workers work without extra configuration. No extra config means no extra failure points.
Basic Setup with Next.js + Neon
Neon is a serverless PostgreSQL service. It provides HTTP-based connections, which pairs well with serverless functions. The free tier offers 0.5GB of storage. Two packages are all it takes to wire it up.
npm install drizzle-orm @neondatabase/serverless
npm install -D drizzle-kit
// lib/db.ts
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);
Just add DATABASE_URL to .env.local. Copy the connection string from the Neon dashboard. Passing the URL to neon() is all it takes to set up an HTTP connection.
Traditional PostgreSQL connections can hit connection limit issues in serverless environments. The Neon HTTP driver handles each request over HTTP, avoiding this problem. If you're using Supabase, use the Transaction Pooler URL — not a Direct Connection.
Schema Definition — Declaring Tables in TypeScript
A Drizzle schema is a TypeScript file. Declare tables with pgTable() and specify column types. This single file is both the DB table definition and the source of truth for TypeScript types.
import { pgTable, serial, text, timestamp, boolean } from 'drizzle-orm/pg-core';
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
published: boolean('published').default(false),
createdAt: timestamp('created_at').defaultNow(),
});
// Auto-extracted types
export type Post = typeof posts.$inferSelect;
export type NewPost = typeof posts.$inferInsert;
Use $inferSelect for SELECT result types and $inferInsert for INSERT input types. Reuse these types in API response types or component props. When the schema changes, types update automatically.
Beyond integer, text, boolean, and timestamp, all PostgreSQL column types are supported — json, uuid, numeric, varchar, and more. MySQL- and SQLite-specific types are available through their own separate import paths.
Type-Safe Query Writing
Define the schema in TypeScript and query return types are inferred automatically. There's no separate code generation step like npx prisma generate in Prisma.
import { eq, desc, like } from 'drizzle-orm';
// SELECT
const result = await db.select().from(posts).where(eq(posts.id, 1));
const list = await db.select().from(posts).orderBy(desc(posts.createdAt)).limit(10);
// INSERT
await db.insert(posts).values({ title: 'Title', published: false });
// UPDATE
await db.update(posts).set({ published: true }).where(eq(posts.id, 1));
// DELETE
await db.delete(posts).where(eq(posts.id, 1));
Reference a column incorrectly and you get a compile error — not a runtime error. IDE autocomplete just works too.
Pass a wrong type to INSERT values and you get a compile-time error. Omit a notNull() column and it's caught immediately. DB query mistakes are caught before server deployment.
Migration — drizzle-kit Workflow
Edit the schema file and drizzle-kit detects the changes. It automatically generates a SQL diff and saves it as a migration file. The generated SQL is fully visible — no black box.
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './lib/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: { url: process.env.DATABASE_URL! },
});
# Run migrations
npx drizzle-kit generate # Generate SQL files
npx drizzle-kit migrate # Apply to DB
Generated SQL files accumulate in the drizzle/ folder in numbered order. Commit the migration files to git and the whole team shares the same schema history. The same migrations can be applied to staging and production in order.
push applies the schema directly to the DB without creating migration files. Use it for quick testing during local development. migrate runs the generated SQL files in order. Always use migrate for staging and production deployments.
Supported DBs — Neon, Supabase, Turso, libSQL
Drizzle supports PostgreSQL, MySQL, and SQLite. All the major DB services used in serverless environments provide official integration guides. Only the import path differs per driver.
| DB Service | DB Type | Drizzle Driver | Serverless Optimization | Free Tier |
|---|---|---|---|---|
| Neon | PostgreSQL | drizzle-orm/neon-http | Native support | 0.5GB |
| Supabase | PostgreSQL | drizzle-orm/postgres-js | Transaction Pooler required | 500MB |
| Turso | SQLite (libSQL) | drizzle-orm/libsql | Edge replication support | 9GB |
| PlanetScale | MySQL | drizzle-orm/planetscale-serverless | Native support | None |
| Local SQLite | SQLite | drizzle-orm/better-sqlite3 | N/A | Unlimited |
Turso is a SQLite-based edge DB. Regional replication keeps latency low. The 9GB free tier is plenty for a solo developer.
When using Supabase with Drizzle, the standard approach is to split Auth and DB responsibilities. Handle Auth with @supabase/supabase-js and DB queries with Drizzle. The two SDKs don't conflict.
Drizzle vs Prisma — Full Comparison
Both ORMs support TypeScript and guarantee type safety. The difference is in philosophy. Prisma leans toward higher abstraction; Drizzle stays close to SQL.
| Feature | Drizzle ORM | Prisma |
|---|---|---|
| Bundle Size | ~50KB (gzip ~7KB) | ~1.6MB (Prisma 7) |
| Edge Runtime | Native support | Adapter required |
| Code Generation | Not required | prisma generate required |
| Migration SQL | Directly viewable | Abstracted |
| GUI Tool | Drizzle Studio (beta) | Prisma Studio (stable) |
| Learning Curve | SQL knowledge helps | Can start without SQL |
| Community | Growing fast | Large and stable |
| Best Fit | Solo/small teams, serverless | Large teams |
Using Drizzle doesn't require knowing SQL inside out. But knowing SQL makes it much easier to use. Prisma lets you start without SQL, but complex queries end up requiring raw SQL anyway.
For serverless + Next.js + solo development, go with Drizzle. If the team is large and a GUI like Prisma Studio matters, Prisma isn't a bad choice. If the current stack is serverless, Drizzle is the right call.
Use Case Recommendations — What to Use and When
| Situation | Recommendation | Reason |
|---|---|---|
| Next.js + Vercel serverless | Drizzle + Neon | Minimal cold start, HTTP connection |
| Cloudflare Workers | Drizzle + Turso | SQLite edge replication, minimal latency |
| Using Supabase Auth | Drizzle + Supabase DB | Auth via Supabase SDK, queries via Drizzle |
| Large team, complex schema | Prisma | Prisma Studio, stable community |
| Fast local prototyping | Drizzle + SQLite | File-based, no separate DB install needed |
Use Drizzle for performance-critical APIs and Prisma Studio for places where a GUI is convenient, like admin panels. Both ORMs can point to the same DB. A pragmatic choice is good enough.
Real-World Pattern — Reading Data in Server Components
In Next.js App Router, Server Components run only on the server. Import the db instance directly and use it. No React state management or useEffect needed.
import { db } from '@/lib/db';
import { posts } from '@/lib/schema';
import { desc } from 'drizzle-orm';
export default async function PostsPage() {
const allPosts = await db.select().from(posts).orderBy(desc(posts.createdAt));
return <ul>{allPosts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
// app/api/posts/route.ts — Route Handler
export async function GET() {
const allPosts = await db.select().from(posts);
return Response.json(allPosts);
}
Both Server Components and Route Handlers use the same db instance. Just maintain one lib/db.ts. No connection management code keeps things simple.
The same applies to Server Actions. Call db.insert() directly inside a 'use server' function. Form submissions are handled without a separate API endpoint.
3 Common Sticking Points
The first is the DATABASE_URL format. Neon needs ?sslmode=require appended to the URL. Supabase requires the Transaction Pooler URL — not a Direct Connection — to work properly in serverless. When copying the connection string from the dashboard, select the serverless option.
The second is the limits of type inference. Nullable columns in LEFT JOIN results can be inferred differently than intended. Either explicitly annotate the $inferSelect type or wrap the result in a Partial type to resolve it.
The third is migration conflicts. When multiple branches modify the schema simultaneously, timestamp-based files can collide. It's safer to reconcile migration file order before merging.
FAQ
Q. Is Drizzle ORM faster than Prisma?
By serverless cold start metrics, yes. The bundle size is ~50KB versus Prisma's ~1.5MB — a significant gap. Raw query execution speed depends on the driver and DB performance, so that's not purely an ORM difference.
Q. Does Drizzle ORM work in Edge runtime?
It does. Both Vercel Edge Functions and Cloudflare Workers are supported without extra adapters. Prisma requires a separate Accelerate adapter.
Q. Can an existing Prisma project be migrated to Drizzle?
It's possible. The Prisma schema needs to be manually converted to a Drizzle schema. The drizzle-kit introspect feature can also auto-generate a schema from an existing DB. Existing DB data stays intact.
Q. What are the downsides of Drizzle ORM?
The GUI tool comparable to Prisma Studio is still in beta. Type inference can behave unexpectedly with complex JOIN queries. The community is smaller than Prisma's, which can make finding references harder.
Q. Can Supabase and Drizzle be used together?
Yes. Connect to Supabase PostgreSQL using the drizzle-orm/postgres-js driver. Keep using @supabase/supabase-js for Auth and handle DB queries with Drizzle. The two SDKs don't conflict.
Wrapping Up
Drizzle ORM is a well-matched ORM for serverless Next.js. Bundle size, Edge runtime support, no code generation — all three are practical advantages in a serverless environment. Write queries like plain SQL and TypeScript types just follow along.
Prisma isn't a bad choice. For large teams or when a GUI tool matters, Prisma holds up fine. For solo developers or small serverless projects, the Drizzle + Neon combination is fast and simple.
The figures and feature information in this article are as of April 2026 and are subject to change.
It is recommended to check the latest information through official documentation and release notes.
Related Posts
npm axios Supply Chain Attack (2026-03-31) — Check Versions 1.14.1 and 0.30.4 Right Now
On March 31, 2026, malicious axios versions 1.14.1 and 0.30.4 were published via a hijacked maintainer account. A plain-crypto-js postinstall hook deploys a cross-platform RAT. Microsoft and Google jointly attributed the campaign to North Korea's Sapphire Sleet / UNC1069.
Vercel vs Netlify vs Cloudflare Pages — 2026 Deployment Platforms
Comparing Vercel Fluid Compute, Netlify credit-based billing, and Cloudflare Pages unlimited bandwidth on pricing, free tiers, Next.js compatibility, and edge performance. Numbers from April 2026 official pricing.
Upgraded to Tailwind v4 — Config Files Are Gone
Migrated to Tailwind CSS v4. tailwind.config.js is gone, and configuration is done in a single CSS file. The Rust-based Oxide compiler makes builds 5x faster. Documented the full process of moving from v3 to v4.