Search nomadLab

Drizzle vs Prisma vs Kysely: Choosing a TypeScript ORM in 2026

Prisma 7 dropped its Rust engine and Drizzle joined PlanetScale, which killed both of the easy reasons to pick a side. What is left is a question about how much SQL you want to write.

Updated

For two years this comparison had a lazy answer: Drizzle, unless your team really wants a prisma.schema file. Prisma’s Rust query engine was heavy on serverless, Drizzle’s edge story was better, done.

Both halves of that stopped being true. Prisma 7 removed the Rust engine entirely and the client is now TypeScript. PlanetScale hired the Drizzle core team on 3 March 2026, which ended the “it is a side project” objection. The two arguments people used to settle this both evaporated within a few months of each other.

So the question is open again, and it turns out to be a better question: how much of your SQL do you want to write yourself?

Versions and numbers below came off npm and the vendor docs on 21 August 2026. Prisma is on 7.9.1, Drizzle on 0.45.2, Kysely on 0.29.5. Two of those three are still pre-1.0, which is worth noticing before you read anyone’s stability argument.

The actual axis

A spectrum from the tool writing your SQL to you writing it yourself. Prisma sits furthest left with schema-first models and generated queries. Drizzle's relational query API sits next, then Drizzle's core builder which reads as SQL, and Kysely sits furthest right as a typed query builder with no relations layer. How much SQL do you write? the tool writes it you write it Prisma schema-first best migrations Drizzle, relational nested fetches with `with` same ergonomics as Prisma Kysely no relations, no migrations you know the EXPLAIN plan Drizzle, core reads as SQL, because it is SQL mixes freely with the layer to its left
Drizzle occupies two points on this line and moving between them costs nothing, which is its real advantage. Prisma and Kysely each own one end.

Prisma is schema-first: models in prisma.schema, prisma generate, then a typed client where you write prisma.user.findMany({ where: { posts: { some: { published: true } } } }). Drizzle is code-first, with the schema in TypeScript and queries that look like SQL with types attached. Kysely is not an ORM at all. It is a typed query builder: you hand it your schema as a TypeScript type and build queries that map nearly one to one onto SQL, with no relations, no eager loading, and no migration tool.

The bundle size numbers everyone quotes are comparing different things

You will see “Drizzle is 7 KB, Prisma is 14 MB.” That comparison sets a tree-shaken bundled core against an installed package, and it survives because both numbers are real.

Here are both measurements. Installed footprint, straight from npm: @prisma/client unpacks to about 75 MB, drizzle-orm to about 10 MB across 2,666 files because it ships every dialect, and kysely to about 1.65 MB. All three declare essentially no runtime dependencies, with Prisma carrying one.

Bundled output is the number that matters at the edge, and Prisma’s own engineering post puts the client at 1.6 MB, or 600 KB gzipped, down from 14 MB and 7 MB gzipped. That is an 85 to 90 percent cut and the architectural reason is honest: removing cross-language serialization between the JS runtime and a Rust process removed a real bottleneck. Their published query numbers are specific rather than vague, which I appreciate: findMany over 25,000 rows went from 185 ms to 55 ms, and a complex join from 207 ms to 130 ms.

What this does not mean is that Prisma is now the same weight as Drizzle. 600 KB gzipped is still large next to a tree-shaken Drizzle or Kysely query path. On Cloudflare Workers, where your bundle competes with everything else in the script, that gap is real. On Lambda with a 250 MB unzipped limit it is noise. On a long-running Node server it is irrelevant and you should pick on API taste alone.

I have seen the claim that Prisma 7 made cold starts nine times faster. Prisma’s own post does not put a number on cold starts, only on bundle size and queries, so I would not repeat it.

Downloads, for whatever they are worth

Weekly npm downloads on 21 August 2026: Drizzle 16.9 million, Prisma 13.8 million, Kysely 11.1 million.

Treat that carefully, because npm counts are inflated by CI and transitive installs and say more about how many pipelines run than how many teams chose something. The directionally useful part is that Drizzle is no longer the challenger, and that Kysely is much closer to the other two than comparison posts that omit it would suggest.

How the queries feel

This is what you live with daily. Prisma’s relational API is genuinely pleasant for the common case:

await prisma.user.findUnique({
  where: { id },
  include: {
    posts: {
      where: { published: true },
      take: 10,
      orderBy: { createdAt: "desc" },
      include: { author: true },
    },
  },
});

Drizzle’s relational queries land in nearly the same place, with with in place of include. The difference is not the happy path, it is what happens when you leave it. Prisma’s long tail is window functions, recursive CTEs, lateral joins, and multi-JSON-column work, where you drop into $queryRaw and lose most of your type safety, or you contort the query API into something nobody wants to maintain. Drizzle’s core builder is SQL with types, so moving down a level is not a context switch, and the two styles mix in one file without friction.

Kysely makes you write it and makes writing it pleasant:

const posts = await db
  .selectFrom("posts")
  .innerJoin("users", "users.id", "posts.author_id")
  .where("posts.author_id", "=", id)
  .where("posts.published", "=", true)
  .orderBy("posts.created_at", "desc")
  .limit(10)
  .selectAll(["posts", "users"])
  .execute();

More lines. Also: you know exactly what runs, you can read the EXPLAIN, and a slow query is a thing you fix rather than a thing you negotiate with an abstraction.

Migrations are Prisma’s strongest single feature

prisma migrate dev writes the SQL diff, applies it, regenerates the client, and gets out of the way. prisma db push lets you thrash on the schema early without writing migrations. The history is a clean folder of timestamped SQL.

Drizzle Kit is now in roughly the same league. drizzle-kit generate produces diffs from your TypeScript schema. The diffs are less polished, and the commonly reported rough edge is rename detection proposing a destructive change where a smarter diff would not have. You can hand-edit any migration before applying, and that escape hatch is what makes it acceptable.

Kysely does not claim to do this at all. You write SQL files and run them with a migrator. That is more work, and it is also exactly the workflow a DBA reviewing schema changes wants.

If you are optimizing for velocity on a new project, do not underweight this. It is the clearest gap in the comparison.

The Accelerate line item

Prisma 7 closed the “you cannot run this on Workers” gap. The client now runs on Workers, Bun, Deno Deploy, and Vercel Edge without Accelerate as a hard prerequisite, connecting through driver adapters or an HTTP driver like Neon’s.

It did not close the billing gap. Accelerate is still there for connection pooling and query caching, and the pricing is Free with 60,000 operations, Starter at $10 a month, Pro at $49, and Business at $129, with per-operation rates past the included quota ($0.018 per thousand on Starter, dropping to $0.006 on Business) plus egress. That is reasonable pricing for what it does. It is also a line item that Drizzle and Kysely do not have, because there is no managed proxy in the picture. You still have to solve pooling, but you solve it with PgBouncer or a serverless driver you run.

What migrating costs

Moving between any two of these is a project, not an afternoon.

Prisma to Drizzle on a moderate app, say 20 to 50 models and a few hundred call sites, is realistically one to three weeks for one engineer. Schema translation is mechanical. The time goes into query rewrites: every include becomes a with, every operator changes shape from { gt: 5 } to gt(col, 5), and Prisma’s automatic _count aggregations become manual subqueries. Run both in parallel during cutover.

Prisma to Kysely is bigger, because it is a paradigm change rather than an API change. Three to six weeks for the same app, plus standing up your own migration tooling and codegen. Teams that do this are usually doing it because the abstraction was actively in the way, not because of bundle size.

Drizzle to Kysely is the cheap one. The mental models are close and Drizzle’s core builder is already SQL-shaped.

And the migration nobody plans for: Prisma 6 to 7. The client internals changed substantially, so it is more involved than a typical major bump, and the regression pass on edge deployments deserves real attention. That is not a reason to switch ORMs, but it is a reason to schedule a window.

Where I would land

New product on a long-running Node server, team that wants velocity: Prisma 7. The migration tooling is the best here and the v7 improvements are real. Budget for Accelerate or run your own pooler.

Edge deployment, especially on D1, Turso, or Neon: Drizzle. The bundle gap still holds where it matters, the relational API is good enough that you will not miss Prisma’s, and the PlanetScale backing settles the sustainability question.

A team strong in SQL, with DBAs in review, or a workload where a third of the queries are analytics-shaped: Kysely. More code, more control, and no argument with the tool on the day you have to ship a hairy query.

The failure mode worth naming: picking Prisma because it is the known-safe choice, then spending three months working around its abstractions on a workload that was always going to be SQL-heavy. Boring is not automatically cheap.

Before committing, take the five queries your domain actually runs, including the one you are already dreading, and write them in all three. An afternoon of that tells you more than any comparison, this one included.

Keep reading