← the writing notes 8 min

Drizzle vs Prisma: Best ORM for a Supabase Project

I've wired Supabase up with both Drizzle and Prisma on production projects this year. They're not interchangeable. Here's the honest breakdown of which one actually fits your project and why.

Two mugs of black coffee on a weathered table, overcast London morning light, cinematic grain

Last spring I was three weeks into a SaaS side project, had Supabase wired up, and was staring at a fork in the road: Drizzle or Prisma. I'd used Prisma on probably forty-plus client builds at Seahawk. Comfortable territory. But a junior dev on the project kept pushing for Drizzle, and honestly I was a bit dismissive at first. "It's newer. Less proven. Let's just go Prisma."

I was wrong to wave it off that quickly.

We ended up trying both on different parts of the same codebase (messy, yes, but instructive). What I learned changed how I think about ORM choice entirely. If you're building on Supabase and you're genuinely unsure which to pick, this is the post I wish I'd had.

---

What You're Actually Choosing Between

These two tools solve the same surface-level problem: you don't want to write raw SQL every time you touch the database. But they come from very different philosophies.

Prisma treats your schema as the single source of truth. You define a schema.prisma file, run prisma generate, and get a fully-typed client. It abstracts SQL almost completely. You rarely think in tables and joins; you think in models and relations.

Drizzle sits much closer to SQL. Your schema is defined in TypeScript, your queries look like SQL, and there's no separate CLI-generated client sitting in the middle. It's described as a "TypeScript ORM that feels like SQL" and that's genuinely accurate.

Neither is objectively better. Full stop. The choice depends on your team, your query patterns, and how much you trust Supabase's own tooling to do the heavy lifting.

---

The Supabase Context Changes Everything

Here's the thing most comparison posts miss: Supabase isn't a blank Postgres database. It ships with Row Level Security, realtime subscriptions, auto-generated REST and GraphQL APIs, and its own JavaScript client. You're often already doing a lot through supabase-js before you even touch an ORM.

So the real question isn't just "which ORM is better?" It's "how much of my query logic should go through an ORM versus the Supabase client directly?"

I've seen teams pick Prisma, ignore supabase-js almost entirely, and then wonder why their RLS policies aren't firing. It's because Prisma connects to Postgres directly via the connection string. It bypasses the Supabase PostgREST layer. Your RLS rules? Only enforced if you tell Prisma to SET LOCAL role = authenticated at the session level. That's not difficult to set up, but you have to know it's a thing.

Drizzle has the same issue. Direct Postgres connection, same bypass behaviour. But because Drizzle feels more SQL-native, developers tend to be more aware they're talking raw Postgres, not through the Supabase abstraction.

---

Bundle Size and Cold Starts: The Serverless Argument

If you're deploying to Vercel Edge Functions, Cloudflare Workers, or even standard Vercel Serverless Functions, bundle size is a real concern.

Prisma's generated client is... chunky. The query engine alone is a binary that gets bundled with your deployment. For a while, Prisma deployments on Vercel were producing bundles over 40MB. They've improved this significantly with Prisma Accelerate and the newer engine options, but you're still fighting a weight disadvantage. Cold starts on serverless functions were noticeably slower on one Seahawk fintech project we shipped in late 2023. We measured it: roughly 800ms cold start with Prisma vs. under 200ms after we migrated that specific service to Drizzle.

Drizzle is tiny. Like, embarrassingly small. No binary engine. No runtime code generation. It compiles down to minimal JavaScript and your deployment stays lean. For edge runtimes, it's the obvious choice right now.

That said, if you're running a traditional Node.js server (Express, Fastify, a standard Next.js app on a regular VPS), this gap matters a lot less. A persistent connection pool doesn't care about cold starts.

---

Developer Experience: Where Prisma Still Wins

I'll be honest. Prisma's DX is hard to beat.

The schema file is genuinely pleasant to work with. Migrations are handled by prisma migrate dev and it just works. Prisma Studio (the GUI) has saved me hours of poking around in the Supabase dashboard when I need to inspect data quickly. And the TypeScript types that come out of the generated client are thorough. You get autocompletion on nested relations, on where clauses, on select shapes.

Drizzle's TypeScript support is also excellent, but it requires more upfront thought. You write your schema in TypeScript files, which I actually prefer philosophically. No separate .prisma syntax to learn. But the query builder takes getting used to. Things like complex joins with aggregates aren't as intuitive as Prisma's include syntax.

Schema Migrations: A Real Difference

Prisma generates migration SQL files automatically and tracks them. Drizzle does too, with drizzle-kit , but the workflow feels a bit more manual. You run drizzle-kit generate:pg , get a SQL file, and apply it yourself (or use drizzle-kit push for rapid prototyping). Less magic, more control.

For junior developers, Prisma wins here every time. For solo devs who want to understand exactly what SQL is being run, Drizzle is satisfying in a way Prisma isn't.

---

Raw Query Power and Complex Scenarios

Back in 2019 a client handed me a brief that required extremely complex aggregations: running totals, window functions, conditional grouping. I was using Prisma at the time and I hit the ceiling almost immediately. Prisma's queryRaw exists, but dropping into raw SQL inside an otherwise abstracted codebase feels like cheating, and you lose all type safety.

Drizzle handles this so much better. Window functions, CTEs, lateral joins: it either has a first-class builder for them or you can drop into SQL fragments without losing your TypeScript context. For Supabase projects with genuinely complex reporting or analytics queries, Drizzle gives you more room to grow.

That said, 80% of CRUD applications don't need any of this. If your project is "users create posts, posts have comments", Prisma's expressive relation queries are faster to write and easier for other developers to read at a glance.

---

When to Pick Each One

Let me be direct about this, because I've seen too many people tie themselves in knots trying to find the "objectively correct" answer.

Pick Drizzle if:

  • You're deploying to edge or serverless runtimes where bundle size and cold starts matter
  • Your team is comfortable with SQL and you want transparency in what queries are actually running
  • The project has complex query requirements (reporting, analytics, non-standard aggregations)
  • You're a solo developer or a small team that wants minimal abstraction overhead

Pick Prisma if:

  • You're running a traditional server-side Node.js setup with connection pooling
  • Your team has junior developers who benefit from the guided schema-first workflow
  • The project is CRUD-heavy and relational complexity is moderate
  • You want a mature ecosystem with more third-party tooling, examples, and Stack Overflow answers

One more thing worth naming: Prisma's documentation is better. Substantially. Drizzle's docs have improved a lot in the past year, but Prisma has had longer to build up tutorials, guides, and community resources. If you're learning as you go, that gap is real.

---

Practical Setup Notes for Supabase Specifically

Whichever you pick, a few things apply universally when connecting to Supabase.

  1. Use the connection pooler URI, not the direct connection. Supabase provides a Supabase connection pooler via PgBouncer. For serverless, always use this. Prisma's recommended DATABASE_URL for serverless should point to the pooler endpoint on port 6543.
  2. Disable prepared statements when using PgBouncer. Prisma needs ?pgbouncer=true appended to the URL. Drizzle needs prepare: false set in the Postgres.js or node-postgres config. Skip this and you'll get cryptic errors in production.
  3. RLS is your friend but you have to configure sessions. If you want RLS policies to apply to ORM queries, you'll need to set the Postgres role and JWT claim at the session level. This isn't boilerplate you get for free.
  4. Don't fight Supabase's strengths. Use supabase-js for auth, realtime, and storage. Use your ORM for complex data queries where the Supabase client's filtering falls short. They can coexist in the same project.

---

FAQ

Is Drizzle production-ready in 2024?

Yes. It's being used in production by teams at companies that aren't just weekend side projects. The API has been stable enough for serious work since late 2023. I'd still call Prisma more "battle-tested" simply by virtue of age, but Drizzle isn't a risk anymore.

Can I use both in the same project?

Technically yes. We did exactly this briefly (accidentally, not as a strategy). Don't. The cognitive overhead isn't worth it, and having two different migration systems touching the same database is asking for a bad day. Pick one.

Does Prisma work with Supabase Edge Functions?

Prisma and Supabase Edge Functions (which run on Deno) have had a complicated relationship. Prisma's engine doesn't run natively in Deno. Using Prisma Accelerate or an external pooling setup can work around this, but it adds moving parts. Drizzle has no such issues in Deno environments.

What about type safety? Are they comparable?

Both generate TypeScript types and both integrate well with TypeScript projects. Drizzle's types are derived from your TypeScript schema definitions. Prisma's types come from the generated client. In my experience, Prisma's nested relation types are slightly more ergonomic out of the box, but Drizzle's inference has caught up considerably.

Which is faster at runtime?

Drizzle has a genuine performance edge because there's less runtime overhead between your query and the Postgres wire protocol. In benchmarks, the difference is measurable. In most real applications it's dwarfed by network latency to your database. Don't pick an ORM primarily for raw query speed.

---

The Actual Answer

Drizzle for edge/serverless Supabase projects, or anywhere you want to stay close to the metal. Prisma for team environments, CRUD-heavy apps, and situations where developer onboarding speed matters.

I use Drizzle more now than I did a year ago. But I don't regret the years I spent with Prisma. It made me a better developer, partly by being opinionated enough that I had to understand why I was hitting its limits.

Neither will make or break your project. Your schema design will. Your indexing decisions will. Pick the one that fits the people on your team and get building.

Need this done, not just read?

start a project book 30 minutes