Drizzle ORM in Production: Patterns I Use After 6 Client Projects
PostgreSQLTypeScriptBackend

Drizzle ORM in Production: Patterns I Use After 6 Client Projects

Real Drizzle patterns from shipping it on 6 production apps in the last year — schema design, type safety, migrations, query patterns, and where Drizzle still falls short of Prisma.

HJ
Hassan Javed
April 2026
10 min read

Why Drizzle, why now

I have used Prisma since 2020 and shipped it on 20 plus projects. In the last year I switched my default to Drizzle on 6 new projects. This post is what I learned and where Drizzle still falls behind.

The short version: Drizzle wins on type safety, bundle size, and SQL transparency. Prisma still wins on developer experience for teams new to ORMs, and on the ecosystem around it (Studio, Accelerate, etc.). Pick by team and use case.

What Drizzle does better

SQL transparency

The Drizzle query you write looks like SQL. When something is slow, you can guess what it compiles to without running explain. With Prisma, the generated SQL is sometimes surprising — a findMany with a nested include can be 4 joins or 4 queries depending on the driver.

This matters when debugging. I have spent fewer hours on "why is this query slow" since switching to Drizzle.

Type inference

Drizzle's TypeScript inference is the cleanest I have seen in any ORM. You define your schema, and every query returns a fully-typed result with no codegen step.

With Prisma, you have to run prisma generate after every schema change. Drizzle uses TypeScript's type system natively. No generate, no stale types, no codegen race conditions in CI.

Bundle size

Drizzle's runtime is small enough to run in edge functions. Prisma's query engine is a Rust binary that does not fit in a Cloudflare Worker. If you are deploying to the edge, Drizzle is the only real choice.

What Prisma still does better

Studio

Prisma Studio is a beautiful database GUI that ships with the ORM. Drizzle has Drizzle Studio now, but it is less polished and missing some Prisma features.

Migration ergonomics

Prisma's migration tool — just type prisma migrate dev — is friendlier than Drizzle's two-step (generate then push). For a team new to migrations, Prisma is gentler.

Documentation depth

Prisma has years of docs, tutorials, and Stack Overflow answers. Drizzle is younger and the ecosystem is still catching up. For a junior engineer, Prisma is easier to onboard.

Schema design that scales

A pattern I use on every Drizzle project: schema lives in its own file per resource (users.ts, orders.ts, etc.), each table defined with pgTable, and types exported via $inferSelect for reads and $inferInsert for writes.

Three things matter:

1.Schema per resource — easier to read, easier to grep
2.$inferSelect vs $inferInsert — different types because inserts allow defaults
3.createdAt and updatedAt on every table — non-negotiable for auditability

For multi-tenant apps, add a tenantId column on every resource and a foreign key to the tenant table. This is the foundation for row-level isolation (see my SaaS multi-tenant post).

Query patterns

The repository pattern

I wrap Drizzle queries in a per-resource repository module. Keeps query logic out of route handlers, makes testing easier.

A typical setup: a usersRepo module exports functions like findById(id) and listByTenant(tenantId). Route handlers call usersRepo.listByTenant — they never touch Drizzle directly. This is the single best architectural choice for keeping a Drizzle codebase maintainable past a year.

Transactions

Drizzle transactions are clean. Wrap your work in db.transaction(async (tx) and use tx for all the inserts and updates inside. If anything throws inside the callback, everything rolls back. Use transactions whenever you write to more than one table for a single user action.

Joins vs nested queries

Drizzle gives you both. Two queries with a manual join is sometimes faster than one query with relations, depending on your data shape. Measure with explain analyze before choosing.

For most cases, relational queries are fine and read more clearly. Reach for raw joins when you have a specific perf reason.

Migrations

Drizzle's migration flow:

1.Edit your schema file
2.Run drizzle-kit generate — creates a SQL migration file
3.Review the migration — always, never trust generated migrations blindly
4.Run drizzle-kit migrate to apply

The review step matters. Drizzle's generator is good but not perfect for destructive changes (renaming a column, splitting a table). Always read the SQL before applying.

For production, run migrations as a separate step before deploying app code. Never let the app auto-migrate on boot — too many race conditions, too many ways to corrupt prod.

Where Drizzle still bites you

A few things that are genuinely awkward:

Polymorphic relations

Drizzle does not have first-class polymorphic relations. If you want a "comments" table that can attach to either a "post" or a "user", you write the joining logic by hand.

Prisma has the same limitation, to be fair. Both ORMs assume relational data has fixed shapes.

Computed fields

If you want a fullName field computed from firstName plus lastName, you write it in TypeScript after the query, or in a SQL view. Neither ORM has clean syntax for this.

Soft deletes

No first-class support. You add a deletedAt column and remember to filter on it in every query. I write a helper that wraps common reads with the filter to avoid forgetting.

Drizzle plus Next.js Server Actions

The combination has become my default for new SaaS in 2026. A Server Action calls the repo function, the repo runs the Drizzle query, and types flow all the way from the DB schema to the client component. No API route, no fetch, no manual type definitions.

My Drizzle stack in 2026

PostgreSQL on Supabase or Neon (Neon's branching is genuinely useful)
Drizzle ORM with schema split per resource
Repository pattern wrapping all queries
Drizzle Kit for migrations
Drizzle Studio for ad-hoc exploration
Server Actions in Next.js calling repos directly

TL;DR

Drizzle wins on type inference, SQL transparency, bundle size, edge compatibility
Prisma wins on studio, migration ergonomics, ecosystem depth
Repository pattern keeps Drizzle codebases maintainable
Always review generated migrations before applying
Drizzle plus Next.js Server Actions plus Postgres is my default for new SaaS

If you are starting a new TypeScript backend and want a senior to pick between Drizzle and Prisma for your specific case, or to architect the data layer, contact me.

Related Reads

You might also like