{"id":170,"date":"2026-04-30T05:03:59","date_gmt":"2026-04-30T05:03:59","guid":{"rendered":"https:\/\/abrarqasim.com\/blog\/drizzle-vs-prisma-2026-when-i-actually-switched\/"},"modified":"2026-04-30T05:03:59","modified_gmt":"2026-04-30T05:03:59","slug":"drizzle-vs-prisma-2026-when-i-actually-switched","status":"publish","type":"post","link":"https:\/\/abrarqasim.com\/blog\/drizzle-vs-prisma-2026-when-i-actually-switched\/","title":{"rendered":"Drizzle vs Prisma in 2026: When I Actually Switched (and When I Didn&#8217;t)"},"content":{"rendered":"<p>I switched a side project from Prisma to Drizzle last August, and then I switched a client project from Drizzle back to Prisma in February. So if you&rsquo;re looking for &ldquo;Drizzle is better, here are five reasons,&rdquo; this isn&rsquo;t that post. They&rsquo;re both fine. The trick is figuring out which one fits the project in front of you, and that took me eight months of running both in production to actually understand.<\/p>\n<p>Short version for the impatient: pick Drizzle if you care about bundle size, raw SQL control, and edge runtime support. Pick Prisma if your team wants the friendliest schema-first DX and you&rsquo;re shipping on a long-lived Node server where the runtime cost doesn&rsquo;t show up in your bill. If you want to know how I actually decided each time, read on.<\/p>\n<h2 id=\"what-changed-for-me-between-prisma-and-drizzle\">What changed for me between Prisma and Drizzle<\/h2>\n<p>I&rsquo;d been on Prisma since late 2022. Schema-first, generated client, <code>migrate dev<\/code>, the whole thing. It was fine. The thing that pushed me to try Drizzle was bundle size, specifically when I started shipping more code to Vercel Edge and Cloudflare Workers. The Prisma client (with its query engine binary) is not built for those runtimes the way Drizzle&rsquo;s pure-TS approach is. I&rsquo;d hit cold-start issues that I was patching around with workarounds I didn&rsquo;t love.<\/p>\n<p>Drizzle felt like writing SQL again, which I&rsquo;d missed. Here&rsquo;s the same query in both, against a basic <code>posts<\/code> table joined to <code>users<\/code>:<\/p>\n<pre><code class=\"language-ts\">\/\/ Prisma\nconst posts = await prisma.post.findMany({\n  where: { published: true },\n  include: { author: { select: { id: true, name: true } } },\n  orderBy: { createdAt: 'desc' },\n  take: 10,\n});\n<\/code><\/pre>\n<pre><code class=\"language-ts\">\/\/ Drizzle\nconst rows = await db\n  .select({\n    id: postsTable.id,\n    title: postsTable.title,\n    createdAt: postsTable.createdAt,\n    author: { id: usersTable.id, name: usersTable.name },\n  })\n  .from(postsTable)\n  .leftJoin(usersTable, eq(postsTable.authorId, usersTable.id))\n  .where(eq(postsTable.published, true))\n  .orderBy(desc(postsTable.createdAt))\n  .limit(10);\n<\/code><\/pre>\n<p>The Prisma version is shorter. Reads like a config object. The Drizzle version is more code, but you can almost see the SQL it&rsquo;ll generate just by squinting at it. For a junior dev hitting the codebase cold, the Prisma one is faster to grok. For me, debugging a slow query at 11pm, the Drizzle one is faster to fix.<\/p>\n<h2 id=\"where-drizzle-actually-wins-for-me\">Where Drizzle actually wins for me<\/h2>\n<p>I keep three things on a sticky note above my desk, because I forget them otherwise.<\/p>\n<p>Bundle size. On a Cloudflare Worker, the Drizzle bundle is roughly 100KB. Prisma&rsquo;s accelerate-compatible client is bigger, and the standard client with the Rust query engine isn&rsquo;t really designed for Workers at all. If you&rsquo;re shipping serverless functions or edge code, Drizzle removes a category of pain that Prisma keeps trying to solve and not quite solving.<\/p>\n<p>Edge runtime support. Drizzle works with Neon, PlanetScale, Turso, Cloudflare D1, and Vercel Postgres in the edge runtime, with no extra layer. The <a href=\"https:\/\/orm.drizzle.team\/docs\/get-started-postgresql#http-driver\" rel=\"nofollow noopener\" target=\"_blank\">Drizzle docs on serverless drivers<\/a> walk through it, and it&rsquo;s the kind of setup where I genuinely just followed the page and shipped. Prisma&rsquo;s edge story has gotten better with <a href=\"https:\/\/www.prisma.io\/docs\/accelerate\" rel=\"nofollow noopener\" target=\"_blank\">Prisma Accelerate<\/a>, but you&rsquo;re paying for a connection pool service to make it work.<\/p>\n<p>Raw SQL escape hatches feel native, not bolted on. When you need a window function, a CTE, or <code>ON CONFLICT DO UPDATE<\/code>, Drizzle gives you a SQL template tag that&rsquo;s just SQL with parameter binding:<\/p>\n<pre><code class=\"language-ts\">import { sql } from 'drizzle-orm';\n\nawait db.execute(sql`\n  INSERT INTO views (post_id, day, count)\n  VALUES (${postId}, current_date, 1)\n  ON CONFLICT (post_id, day) DO UPDATE\n  SET count = views.count + 1\n`);\n<\/code><\/pre>\n<p>With Prisma I&rsquo;d find myself dropping into <code>$queryRaw<\/code> more often than I wanted, and at that point I&rsquo;m half on the ORM and half off it.<\/p>\n<h2 id=\"where-prisma-still-wins-for-me\">Where Prisma still wins for me<\/h2>\n<p>OK, it&rsquo;s not all on Drizzle&rsquo;s side. There are three places where Prisma still does it better, and I have to keep reminding myself so I don&rsquo;t get carried away.<\/p>\n<p>Migrations. Prisma&rsquo;s migration story is the cleanest one I&rsquo;ve used in TypeScript. <code>prisma migrate dev<\/code> reads your schema, diffs against the DB, generates a SQL migration, applies it. Drizzle&rsquo;s migration tooling has gotten much better in 2025, but it&rsquo;s not at the same level. With Drizzle I still occasionally hand-edit a generated migration when the diff isn&rsquo;t quite what I want. With Prisma I almost never do.<\/p>\n<p>Schema readability. The <code>schema.prisma<\/code> file is genuinely nice to skim:<\/p>\n<pre><code class=\"language-prisma\">model Post {\n  id        Int      @id @default(autoincrement())\n  title     String\n  published Boolean  @default(false)\n  authorId  Int\n  author    User     @relation(fields: [authorId], references: [id])\n  createdAt DateTime @default(now())\n\n  @@index([published, createdAt])\n}\n<\/code><\/pre>\n<p>Pull up a Prisma project you haven&rsquo;t touched in six months, open <code>schema.prisma<\/code>, and you can see your data model in two minutes. Drizzle&rsquo;s schema is plain TypeScript, which is more flexible but harder to read at a glance. On a small team that&rsquo;s a wash. On a team where someone less familiar with TypeScript has to read the schema, Prisma wins.<\/p>\n<p>Tooling and docs. Prisma Studio is a real tool that real people use. The error messages are written for humans. The docs are exhaustive. Drizzle&rsquo;s docs have improved a lot, but if I&rsquo;m onboarding a new dev who&rsquo;s never seen either ORM, I can hand them the Prisma docs and they&rsquo;ll be productive in a day.<\/p>\n<h2 id=\"the-actual-switching-cost-this-is-the-bit-nobody-talks-about\">The actual switching cost (this is the bit nobody talks about)<\/h2>\n<p>Switching ORMs sounds easy if you&rsquo;ve never done it. It isn&rsquo;t.<\/p>\n<p>When I moved my side project from Prisma to Drizzle, the schema rewrite took me about an hour. The query rewrites took me a weekend, because every <code>.findMany<\/code> with <code>include<\/code> had to become a <code>select<\/code> with a <code>leftJoin<\/code>, and I had to think about each one. The third bucket was the part I didn&rsquo;t expect: types. Prisma generates types like <code>Post &amp; { author: User }<\/code> automatically. With Drizzle you build the return type yourself, or you use <code>$inferSelect<\/code>, or you pull from your <code>select<\/code> clause. It&rsquo;s not bad, just different, and your existing type signatures don&rsquo;t carry over for free.<\/p>\n<p>If your codebase has 200 queries, plan on a week of work, not an afternoon. If you&rsquo;re at 50 queries, two days. I&rsquo;ve seen teams underestimate this and resent the migration halfway through. Don&rsquo;t be that team. I learned this the hard way, which is also how I <a href=\"https:\/\/abrarqasim.com\/blog\/nextjs-server-actions-mistakes-i-made\" rel=\"noopener\">learned to be careful with Next.js server actions<\/a> \u2014 that migration cost story is the same shape: looks easy, isn&rsquo;t.<\/p>\n<h2 id=\"my-current-rule-of-thumb\">My current rule of thumb<\/h2>\n<p>When I start a new project in 2026, my decision tree looks roughly like this. New Next.js 15 app on Vercel Edge or Cloudflare? Drizzle. New Node server with a long-lived runtime, no edge constraints, mid-sized team? Prisma. Existing Prisma codebase that&rsquo;s working fine? Don&rsquo;t migrate just to migrate. Existing Drizzle codebase where someone keeps writing terrible joins? Add a code review checklist before you blame the ORM.<\/p>\n<p>For client work I have a simpler rule: I pick the one the existing team already knows. The cost of an ORM switch on a project I don&rsquo;t own day-to-day is rarely worth it. I&rsquo;d rather optimize the slow queries than relitigate the data layer.<\/p>\n<p>If you want to see how this kind of thing plays out in production code, I keep a few of these patterns in <a href=\"https:\/\/abrarqasim.com\/work\" rel=\"noopener\">my work<\/a>, where I&rsquo;ve been writing both side by side for the last year.<\/p>\n<h2 id=\"what-to-try-this-week\">What to try this week<\/h2>\n<p>Pick one query in your current ORM that you&rsquo;ve been unhappy with. Maybe it&rsquo;s the one that needs an index hint, or the one with three nested includes that&rsquo;s secretly running five queries. Write the same thing in the other ORM. Don&rsquo;t migrate the whole codebase, just write one query both ways and look at the SQL each one produces. Drizzle has a <code>.toSQL()<\/code> method that prints the generated SQL. Prisma has the <a href=\"https:\/\/www.prisma.io\/docs\/orm\/prisma-client\/observability-and-logging\/logging\" rel=\"nofollow noopener\" target=\"_blank\">query log<\/a> you can turn on with <code>log: ['query']<\/code>. Run both, compare, decide.<\/p>\n<p>That&rsquo;s the test I wish I&rsquo;d run a year ago. It would have saved me a weekend.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Honest take on Drizzle vs Prisma after running both in production. When I switched my Next.js project, when Prisma still wins, and what tripped me up.<\/p>\n","protected":false},"author":2,"featured_media":169,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"","rank_math_description":"Honest take on Drizzle vs Prisma after running both in production. When I switched my Next.js project, when Prisma still wins, and what tripped me up.","rank_math_focus_keyword":"drizzle vs prisma","rank_math_canonical_url":"","rank_math_robots":"","footnotes":""},"categories":[147,156],"tags":[180,183,61,182,181,63],"class_list":["post-170","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-backend","category-typescript","tag-drizzle","tag-edge-runtime","tag-nextjs","tag-orm","tag-prisma","tag-typescript"],"_links":{"self":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/posts\/170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/comments?post=170"}],"version-history":[{"count":0,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/posts\/170\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/media\/169"}],"wp:attachment":[{"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/media?parent=170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/categories?post=170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/abrarqasim.com\/blog\/wp-json\/wp\/v2\/tags?post=170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}