Dev Tools11 min

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)

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.

Quick Take
  • 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

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.

# Install
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.

Serverless Connection Pool Notes

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.

// lib/schema.ts
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.

// Use directly in Server Components
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.

// drizzle.config.ts
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.

drizzle-kit push vs migrate

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 ServiceDB TypeDrizzle DriverServerless OptimizationFree Tier
NeonPostgreSQLdrizzle-orm/neon-httpNative support0.5GB
SupabasePostgreSQLdrizzle-orm/postgres-jsTransaction Pooler required500MB
TursoSQLite (libSQL)drizzle-orm/libsqlEdge replication support9GB
PlanetScaleMySQLdrizzle-orm/planetscale-serverlessNative supportNone
Local SQLiteSQLitedrizzle-orm/better-sqlite3N/AUnlimited

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.

FeatureDrizzle ORMPrisma
Bundle Size~50KB (gzip ~7KB)~1.6MB (Prisma 7)
Edge RuntimeNative supportAdapter required
Code GenerationNot requiredprisma generate required
Migration SQLDirectly viewableAbstracted
GUI ToolDrizzle Studio (beta)Prisma Studio (stable)
Learning CurveSQL knowledge helpsCan start without SQL
CommunityGrowing fastLarge and stable
Best FitSolo/small teams, serverlessLarge 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

SituationRecommendationReason
Next.js + Vercel serverlessDrizzle + NeonMinimal cold start, HTTP connection
Cloudflare WorkersDrizzle + TursoSQLite edge replication, minimal latency
Using Supabase AuthDrizzle + Supabase DBAuth via Supabase SDK, queries via Drizzle
Large team, complex schemaPrismaPrisma Studio, stable community
Fast local prototypingDrizzle + SQLiteFile-based, no separate DB install needed
Using Drizzle and Prisma Together Is Also an Option

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.

// app/posts/page.tsx — Server Component
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.

Share