<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mr. S Gupta</title>
    <description>The latest articles on DEV Community by Mr. S Gupta (@surajsrggupta).</description>
    <link>https://dev.to/surajsrggupta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4035061%2F5c94ecc6-7f77-4e5d-b1d1-eff09aea4855.png</url>
      <title>DEV Community: Mr. S Gupta</title>
      <link>https://dev.to/surajsrggupta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/surajsrggupta"/>
    <language>en</language>
    <item>
      <title>Prisma vs Drizzle vs Raw SQL: What Every Backend Developer Should Understand Before Choosing an ORM</title>
      <dc:creator>Mr. S Gupta</dc:creator>
      <pubDate>Fri, 28 Aug 2026 11:09:05 +0000</pubDate>
      <link>https://dev.to/surajsrggupta/prisma-vs-drizzle-vs-raw-sql-what-every-backend-developer-should-understand-before-choosing-an-orm-11ch</link>
      <guid>https://dev.to/surajsrggupta/prisma-vs-drizzle-vs-raw-sql-what-every-backend-developer-should-understand-before-choosing-an-orm-11ch</guid>
      <description>&lt;p&gt;When most developers start building backend applications, they're usually focused on one thing, getting an API working. Express routes, controllers, some auth, a bit of middleware, that's usually the whole mental model in the beginning.&lt;/p&gt;

&lt;p&gt;But sooner or later, a bigger question shows up. How exactly should your application be talking to the database?&lt;/p&gt;

&lt;p&gt;And that's when a bunch of unfamiliar words start floating around. Raw SQL, database drivers, ORMs, Prisma, Drizzle, query builders. Some people will tell you to never touch an ORM and just write SQL yourself. Others will swear Prisma made their life ten times easier. And then there's a smaller crowd that prefers Drizzle specifically because it stays close to SQL instead of hiding it.&lt;/p&gt;

&lt;p&gt;So what's actually going on here? Why do all these tools even exist, and how do you know which one to reach for? Let's build this up from the ground.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, understand how data actually moves
&lt;/h2&gt;

&lt;p&gt;Before Prisma or Drizzle mean anything to you, it helps to see the full picture of how a request travels through a backend app.&lt;/p&gt;

&lt;p&gt;Say a user opens your site and clicks something like "show my profile." That click travels roughly like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser

   |
   v

Express API

   |
   v

Database Layer

   |
   v

PostgreSQL Database

   |
   v

Response back to the user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That "database layer" bit in the middle is where all the confusion tends to live. Your app needs some way to actually talk to PostgreSQL, and there are basically three common ways to do that: writing raw SQL yourself, using an ORM like Prisma, or using a query builder like Drizzle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing raw SQL directly
&lt;/h2&gt;

&lt;p&gt;This is the oldest, most direct route there is, you just write the SQL yourself.&lt;/p&gt;

&lt;p&gt;Say you've got a users table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users

id
name
email
password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finding a user is as simple as this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database speaks SQL natively, so there's no translation happening anywhere.&lt;/p&gt;

&lt;p&gt;In Node.js, if you're on PostgreSQL, the &lt;code&gt;pg&lt;/code&gt; package is the usual way to send queries like that directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Pool&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;connectionString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM users WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your code sends SQL, PostgreSQL runs it, and the data comes straight back. Nothing hidden, nothing abstracted away.&lt;/p&gt;

&lt;p&gt;Writing SQL yourself gives you complete control, obviously. You can write things like this without fighting any abstraction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For gnarly reports like that, SQL is genuinely hard to beat. Writing it yourself also forces you to actually understand joins, indexes, execution plans, and performance in general, which is knowledge that pays off no matter what tool you end up using later. And there's no extra layer sitting between your code and the database either.&lt;/p&gt;

&lt;p&gt;But raw SQL has real downsides once a project grows past a handful of queries. Imagine a codebase with hundreds of them scattered around.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="s2"&gt;`
SELECT *
FROM users
WHERE email=$1
`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine someone renames a column somewhere down the line, say &lt;code&gt;email&lt;/code&gt; becomes &lt;code&gt;email_address&lt;/code&gt;. Every query touching that column is now quietly broken, and the database knows about the change immediately. Your TypeScript code has no idea until something crashes at runtime.&lt;/p&gt;

&lt;p&gt;There's a sneakier version of this problem too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emial&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spot the typo, &lt;code&gt;emial&lt;/code&gt; instead of &lt;code&gt;email&lt;/code&gt;. JavaScript won't say a word about it. You only find out once that line actually executes and blows up. This exact pain point is basically why ORMs exist in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what is an ORM, really
&lt;/h2&gt;

&lt;p&gt;ORM stands for Object Relational Mapping, which sounds fancier than it actually is. All it really means is that there's a bridge sitting between your programming language and your database.&lt;/p&gt;

&lt;p&gt;Instead of writing this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You end up writing something closer to this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ORM takes what you wrote and turns it into actual SQL behind the scenes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your TypeScript code

        |
        v

ORM

        |
        v

SQL query

        |
        v

Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Developers reach for ORMs because modern apps need more than just sending queries around. They need type safety, proper migrations, schema management that doesn't require memorizing every table by hand, and honestly, just less repetitive boilerplate. That's the gap ORMs are trying to close.&lt;/p&gt;

&lt;p&gt;In the TypeScript world today, the names that come up most are Prisma, Drizzle, TypeORM, and Sequelize. This piece focuses mainly on raw SQL, Prisma, and Drizzle, since those three are what most modern TypeScript backend projects are actually choosing between right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting into Prisma
&lt;/h2&gt;

&lt;p&gt;Prisma is easily one of the most talked about ORMs in the TypeScript world, and it's usually one of the first names that comes up in any conversation about modern Node.js backends. So what problem is it actually solving?&lt;/p&gt;

&lt;p&gt;At its core, Prisma lets your TypeScript app talk to a database using regular TypeScript code instead of SQL scattered everywhere. It supports PostgreSQL, MySQL, SQLite, SQL Server, and MongoDB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeScript code

        |
        v

Prisma Client

        |
        v

SQL queries

        |
        v

Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You write TypeScript, Prisma turns it into the actual queries.&lt;/p&gt;

&lt;p&gt;A typical Express plus Prisma plus PostgreSQL setup ends up looking roughly like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client

  |
  v

Express API

  |
  v

Service Layer

  |
  v

Prisma Client

  |
  v

PostgreSQL Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prisma Client is really the piece doing all the work here, it's the actual bridge between your backend code and the database sitting behind it.&lt;/p&gt;

&lt;p&gt;Everything starts with a file called &lt;code&gt;schema.prisma&lt;/code&gt;, which defines your entire database structure in one place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;       &lt;span class="nx"&gt;Int&lt;/span&gt;    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;autoincrement&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;    &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;unique&lt;/span&gt;
  &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's basically saying, create a &lt;code&gt;User&lt;/code&gt; table with these four columns, and Prisma understands exactly what that means.&lt;/p&gt;

&lt;p&gt;Where raw SQL would need something like this to create the table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prisma just needs the schema block shown above, and it handles turning that into actual database changes through something called a migration.&lt;/p&gt;

&lt;p&gt;A migration is really just a recorded history of database changes over time. Say your User table starts out simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User

id
name
email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Months later you decide to add a phone number field. Instead of manually altering the table yourself, you run something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma migrate dev &lt;span class="nt"&gt;--name&lt;/span&gt; add_phone_number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prisma generates a migration file to track that change, something like a folder with &lt;code&gt;001_initial_setup&lt;/code&gt; followed by &lt;code&gt;002_add_phone_number&lt;/code&gt;, so your entire database history stays saved and versioned instead of living only in someone's memory.&lt;/p&gt;

&lt;p&gt;Once your schema's defined, Prisma generates a client you actually use in your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes, that quietly becomes this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You never had to type that SQL yourself.&lt;/p&gt;

&lt;p&gt;The common operations map over pretty intuitively too. Creating a record that would normally be an &lt;code&gt;INSERT INTO users (name, email) VALUES (...)&lt;/code&gt; becomes &lt;code&gt;prisma.user.create({ data: { name, email } })&lt;/code&gt;. Fetching all users, which would be a plain &lt;code&gt;SELECT * FROM users&lt;/code&gt;, becomes &lt;code&gt;prisma.user.findMany()&lt;/code&gt;. Updating a record swaps &lt;code&gt;UPDATE users SET name='Aman' WHERE id=1&lt;/code&gt; for &lt;code&gt;prisma.user.update({ where: { id: 1 }, data: { name: "Aman" } })&lt;/code&gt;. And deleting swaps &lt;code&gt;DELETE FROM users WHERE id=1&lt;/code&gt; for &lt;code&gt;prisma.user.delete({ where: { id: 1 } })&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Where Prisma really earns its popularity is type safety. If your schema defines a &lt;code&gt;User&lt;/code&gt; with &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;email&lt;/code&gt;, then writing something like this actually gives you working autocomplete on every field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you accidentally typo it as &lt;code&gt;user[0].emali&lt;/code&gt;, Prisma paired with TypeScript will flag that before your app even runs, which saves a genuinely surprising amount of debugging time down the line.&lt;/p&gt;

&lt;p&gt;Real applications almost never have just one table either. Say a user has many posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User

id
name

Post

id
title
userId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prisma represents that relationship directly in the schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="nx"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;autoincrement&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

 &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;

 &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

 &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="nx"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;autoincrement&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

 &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;

 &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="nx"&gt;Int&lt;/span&gt;

 &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="nx"&gt;references&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And fetching a user along with their posts becomes a single readable call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
  &lt;span class="na"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which gives you back something like a user object with a nested posts array, exactly the shape you'd want to work with in your app.&lt;/p&gt;

&lt;p&gt;Prisma's biggest strengths really come down to how natural the developer experience feels, how strong the type safety is especially in TypeScript projects, how organized migrations become, how solid the documentation is, and how easily a whole team can look at the schema and immediately understand the database structure.&lt;/p&gt;

&lt;p&gt;It's not without trade-offs though. Genuinely complex reporting queries can start feeling awkward compared to just writing raw SQL. Because Prisma hides SQL so effectively, developers who only ever learn Prisma can end up struggling later when they actually need to optimize something at the database level. And there's technically an extra layer sitting in the request flow, application to Prisma to SQL to database, instead of the more direct application to SQL to database path. For most apps that extra layer is a complete non issue, but it's worth knowing it's there.&lt;/p&gt;

&lt;p&gt;Prisma tends to make the most sense when you're building APIs in TypeScript, want fast development, mostly need standard CRUD operations, and care a lot about developer experience. A lot of startups and SaaS products lean on it for exactly these reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Drizzle fits into the picture
&lt;/h2&gt;

&lt;p&gt;Drizzle is the other ORM that's picked up serious momentum in the TypeScript world, but understanding it really comes down to understanding one thing first, Prisma and Drizzle are built on genuinely different philosophies.&lt;/p&gt;

&lt;p&gt;Prisma's whole approach is keeping developers away from database complexity as much as possible. Drizzle takes the opposite stance, keep developers close to SQL, just give them TypeScript's safety on top of it. Both are chasing the same end goal, a better development experience around your database, they just take very different roads to get there.&lt;/p&gt;

&lt;p&gt;Drizzle is a lightweight TypeScript ORM that works with PostgreSQL, MySQL, and SQLite, and its whole focus is type safety, performance, staying close to SQL, and keeping the architecture lightweight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeScript code

        |
        v

Drizzle ORM

        |
        v

SQL query

        |
        v

Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The philosophy difference is easiest to see side by side. Fetching all users in Prisma looks like this, and you never really need to think about what SQL it's generating underneath.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drizzle asks you to write something noticeably closer to actual SQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersTable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can basically read what's happening at the database level just by looking at the code.&lt;/p&gt;

&lt;p&gt;Schemas work differently too. Where Prisma defines things in its own &lt;code&gt;schema.prisma&lt;/code&gt; file, Drizzle defines the schema directly in TypeScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;pgTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;varchar&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;drizzle-orm/pg-core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pgTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

 &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;

 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

 &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So your database structure literally lives inside your TypeScript codebase, no separate schema language to learn.&lt;/p&gt;

&lt;p&gt;The common operations feel like a TypeScript flavored version of SQL itself. Inserting a row that would be &lt;code&gt;INSERT INTO users (name, email) VALUES (...)&lt;/code&gt; in SQL becomes &lt;code&gt;db.insert(users).values({ name, email })&lt;/code&gt; in Drizzle. Fetching everything, which is &lt;code&gt;SELECT * FROM users&lt;/code&gt;, becomes &lt;code&gt;db.select().from(users)&lt;/code&gt;. And filtering, which would be &lt;code&gt;SELECT * FROM users WHERE id=1&lt;/code&gt;, becomes &lt;code&gt;db.select().from(users).where(eq(users.id, 1))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;People gravitate toward Drizzle for a handful of reasons. It's genuinely lightweight with very little unnecessary abstraction sitting in the way. Because it stays close to SQL, your actual SQL knowledge stays sharp and keeps growing rather than getting hidden behind an abstraction. The queries it generates tend to be predictable since there's less machinery translating your intent. And it was built with modern runtimes in mind too, things like edge environments and serverless setups.&lt;/p&gt;

&lt;p&gt;That said, if you've never really learned SQL, Drizzle can feel a lot more confusing upfront than Prisma does, since Prisma is generally the easier on-ramp for total beginners. Using Drizzle well also genuinely requires understanding joins, relations, indexes, and how queries actually work, there's no hiding from that. And its ecosystem, documentation, and community, while solid, are still smaller than Prisma's more mature setup.&lt;/p&gt;

&lt;p&gt;The simplest way to frame the difference is this. With Prisma you treat the database like a bunch of objects, &lt;code&gt;prisma.user.findMany()&lt;/code&gt;, and the whole focus is developer experience. With Drizzle you treat the database more like SQL itself, &lt;code&gt;db.select().from(users)&lt;/code&gt;, and the focus shifts toward performance and control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking at all three side by side
&lt;/h2&gt;

&lt;p&gt;At this point we've covered three real approaches, raw SQL, Prisma, and Drizzle, and architecturally they stack up like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raw SQL:      Application → SQL Query → Database
Prisma:       Application → Prisma Client → SQL → Database
Drizzle:      Application → Drizzle → SQL → Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take one simple operation, finding a user by email, given a basic users table with &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;email&lt;/code&gt;. Here's how each approach handles the exact same task.&lt;/p&gt;

&lt;p&gt;Raw SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="s2"&gt;`
SELECT *
FROM users
WHERE email=$1
`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rahul@test.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prisma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
 &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rahul@test.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drizzle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rahul@test.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three get you the exact same data back at the end of the day. What actually differs is how much control you want, how much abstraction you're comfortable with, and how much SQL you already know going in.&lt;/p&gt;

&lt;p&gt;A mistake a lot of beginners make here is fixating on "which one's the fastest," when in real projects that's rarely the question that actually matters. The better questions are usually things like what the team's already comfortable with, how complex the project genuinely is, how strong everyone's database knowledge actually is, and how complicated the queries are likely to get. A simple SaaS app can usually get by just fine on Prisma alone. A database heavy application is where Drizzle, or even raw SQL in places, starts earning its keep.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Raw SQL&lt;/th&gt;
&lt;th&gt;Prisma&lt;/th&gt;
&lt;th&gt;Drizzle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Learning curve&lt;/td&gt;
&lt;td&gt;Harder&lt;/td&gt;
&lt;td&gt;Easier&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Control&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type Safety&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer Experience&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex Queries&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Beginner Friendly&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  So what should you actually choose
&lt;/h2&gt;

&lt;p&gt;Should you always default to using an ORM? No, honestly. An ORM is a tool like any other, and no single tool is the right call for every project out there. Some apps genuinely move faster with one, others are better off without.&lt;/p&gt;

&lt;p&gt;Raw SQL earns its place when you need maximum control over the database, when the app is genuinely database heavy, when queries get complex, or when performance really can't take a hit. Think analytics platforms, reporting systems, financial applications, or anything doing heavy data processing. Say you need a report answering something like "how much has each customer purchased over the last five years, and what's their average order value." That kind of query is just naturally easier to express directly in SQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;

&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;

&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;

&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's really no substitute for SQL's raw power in cases like that. The catch is that leaning entirely on raw SQL across a large codebase gets unwieldy fast, hundreds of scattered query files, and you're left manually managing type safety yourself on top of it all.&lt;/p&gt;

&lt;p&gt;Prisma tends to be the better call when you're building a TypeScript backend, doing mostly standard CRUD work, care about development speed, and have multiple developers working across the same codebase. Think SaaS products, admin dashboards, e-commerce APIs, or content management systems, basically anywhere operations like creating a user, updating a profile, creating an order, or pulling dashboard data are the daily bread and butter. Prisma genuinely boosts productivity here, turning something like a raw &lt;code&gt;SELECT * FROM users WHERE id=1&lt;/code&gt; into a clean, readable &lt;code&gt;prisma.user.findUnique({ where: { id: 1 } })&lt;/code&gt; that any teammate can understand at a glance.&lt;/p&gt;

&lt;p&gt;Drizzle earns its spot when you're working in TypeScript, already know SQL reasonably well, care a lot about performance and control, and want something lightweight rather than heavy handed. It tends to appeal to developers who want the safety net of an ORM without feeling like they've been pulled too far away from the actual database.&lt;/p&gt;

&lt;p&gt;In practice, plenty of real projects don't stick to just one approach. A startup might reasonably begin like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Express → Prisma → PostgreSQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is a genuinely practical starting point. As the app grows and analytics or complex reporting needs pile up, it's common to start layering raw SQL into specific parts of the app rather than ripping out Prisma entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
├── Prisma
└── Raw SQL Queries
        ↓
   PostgreSQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using one approach everywhere isn't some rule you're required to follow, and most real world codebases end up mixing them anyway. Startups often lean toward TypeScript plus Prisma plus PostgreSQL purely for development speed. Newer, more modern TypeScript projects increasingly reach for Drizzle instead, valuing that lightweight, SQL friendly approach. And larger scale systems often end up combining an ORM with raw SQL and dedicated database optimization work, simply because different parts of a large system run into genuinely different problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes worth avoiding
&lt;/h2&gt;

&lt;p&gt;A few things trip people up consistently here. The first is treating the ORM itself as the database. Prisma isn't a database, Drizzle isn't a database, they're just tools for accessing one, whether that's PostgreSQL, MySQL, or MongoDB sitting underneath.&lt;/p&gt;

&lt;p&gt;The second is skipping SQL entirely and jumping straight to Prisma. It feels productive early on, but it tends to backfire later when slow queries stop making sense, joins feel needlessly confusing, and database optimization becomes genuinely hard because there's no real foundation underneath the abstraction. An ORM was never meant to replace SQL, it's a layer sitting on top of it.&lt;/p&gt;

&lt;p&gt;The third is chasing raw performance numbers above everything else. Developer productivity matters just as much in the real world. Shaving five milliseconds off a query while making development three months slower isn't automatically the smarter trade to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  A learning path worth following
&lt;/h2&gt;

&lt;p&gt;If starting from zero today, this is roughly the order worth going in. Start with SQL fundamentals, tables, primary keys, foreign keys, joins, indexes, transactions, all using something like PostgreSQL. Then spend some real time connecting directly with something like Node's &lt;code&gt;pg&lt;/code&gt; package, so you actually understand how an application talks to a database without anything hidden in between. From there, move into Prisma, get comfortable with schemas, migrations, relations, and the type safety it brings. And finally, give Drizzle a proper try, so you understand what an SQL-first approach with a query builder actually feels like, along with the performance trade-offs that come with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where that leaves you
&lt;/h2&gt;

&lt;p&gt;The point of an ORM was never to replace SQL. It's there to make the developer experience better, nothing more grand than that.&lt;/p&gt;

&lt;p&gt;A genuinely strong backend developer isn't someone who just happens to know Prisma or Drizzle well. It's someone who understands how a database actually works, how to write SQL when it's needed, what an ORM is actually simplifying for them, and just as importantly, when reaching for an ORM makes sense and when writing raw SQL directly is the smarter call.&lt;/p&gt;

&lt;p&gt;Once that clarity sets in, choosing between these tools stops feeling like a guessing game. You start making the call based on what the project actually needs, not on whatever's trending that particular month.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>prisma</category>
      <category>drizzle</category>
      <category>database</category>
    </item>
    <item>
      <title>Is Supabase Actually a Database?</title>
      <dc:creator>Mr. S Gupta</dc:creator>
      <pubDate>Thu, 20 Aug 2026 14:44:18 +0000</pubDate>
      <link>https://dev.to/surajsrggupta/is-supabase-actually-a-database-5bi8</link>
      <guid>https://dev.to/surajsrggupta/is-supabase-actually-a-database-5bi8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Is Supabase Actually a Database? Sorting Out Supabase, Firebase, Appwrite, PocketBase, and Neon&lt;/strong&gt;&lt;br&gt;
For a good chunk of my early days learning backend stuff, I genuinely believed Supabase, Firebase, and Appwrite were databases. Just straight up databases, no different from PostgreSQL or MongoDB in my head.&lt;/p&gt;

&lt;p&gt;And honestly, the way tutorials talk about them didn't help at all. One video would tell you to just use Supabase and move on. The next would swear by Firebase instead. Then someone else would come along and say skip all of that, just learn PostgreSQL properly.&lt;/p&gt;

&lt;p&gt;At some point I genuinely lost track of what I was even picking between. Was I choosing a database? A backend? Some kind of hosting service? Honestly I couldn't tell you at the time.&lt;/p&gt;

&lt;p&gt;If that confusion sounds familiar, this should clear most of it up.&lt;/p&gt;
&lt;h2&gt;
  
  
  The one thing you need to get straight first
&lt;/h2&gt;

&lt;p&gt;A database and a backend platform are not the same thing, and mixing them up is where basically all the confusion starts.&lt;/p&gt;

&lt;p&gt;Think about building a house for a second. You need bricks, sure, but you also need wiring, plumbing, security systems, furniture, all of it. The bricks are just one piece of a much bigger picture.&lt;/p&gt;

&lt;p&gt;A database works the same way inside your backend. It's just one piece of the whole thing. Modern platforms tend to bundle a bunch of backend services together under one roof, and that's exactly why people end up mistaking the whole platform for just the database part.&lt;/p&gt;
&lt;h2&gt;
  
  
  So what does a database actually do
&lt;/h2&gt;

&lt;p&gt;A database really only has one job, and it's not glamorous. It stores your data. That's the entire job description.&lt;/p&gt;

&lt;p&gt;Take PostgreSQL for example. It stores things in tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Users&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;email&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Rahul&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:rahul@example.com"&gt;rahul@example.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Aman&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:aman@example.com"&gt;aman@example.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It genuinely doesn't care what you're building on top of it, whether that's an online store, a social app, or some banking system. Its only concern is storing and pulling back data when asked.&lt;/p&gt;
&lt;h2&gt;
  
  
  Okay, so what is Supabase then
&lt;/h2&gt;

&lt;p&gt;Here's the thing people keep getting wrong. Supabase is not a database.&lt;/p&gt;

&lt;p&gt;Supabase is a backend platform, and one of the things it happens to include is a PostgreSQL database.&lt;/p&gt;

&lt;p&gt;Picture it more like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Supabase

├── PostgreSQL Database
├── Authentication
├── File Storage
├── Realtime Engine
├── Edge Functions
├── Dashboard
└── APIs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how the database is just one item in that list, not the whole thing. Supabase basically hands you a bunch of backend pieces that are already wired together, so instead of setting up each one separately, you get a working backend pretty much out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if you skip Supabase entirely
&lt;/h2&gt;

&lt;p&gt;Nothing's actually stopping you from building this exact same setup yourself, piece by piece.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Express

├── PostgreSQL
├── JWT Authentication
├── AWS S3 Storage
├── Socket.IO
├── REST API
└── Docker Deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get total control doing it this way, no argument there. But you're also signing up for a lot more setup work, and honestly a lot more things that can go wrong along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  And Firebase
&lt;/h2&gt;

&lt;p&gt;Firebase is also a backend platform, but it's built around a different core. Instead of PostgreSQL, its main database is Firestore, which is a document database, meaning your data lives as documents rather than rows in a table.&lt;/p&gt;

&lt;p&gt;Firebase brings along its own bundle of services too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Firebase

├── Firestore
├── Authentication
├── Cloud Functions
├── Cloud Storage
├── Analytics
├── Hosting
└── Push Notifications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've ever built an Android app, you've probably had Firebase suggested to you constantly, and that's mostly because Google has baked it so deeply into its mobile ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  So is Firebase actually better than Supabase
&lt;/h2&gt;

&lt;p&gt;There's no clean answer here, and honestly anyone who gives you one confidently is probably oversimplifying. They're just solving different problems.&lt;/p&gt;

&lt;p&gt;Supabase makes a lot of sense if you're comfortable with PostgreSQL and SQL in general. Firebase makes more sense if your app genuinely benefits from Firestore's structure or from being deep in Google's ecosystem. Which one wins really comes down to what you're building, not which platform is objectively superior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does Appwrite fit in
&lt;/h2&gt;

&lt;p&gt;Appwrite is chasing a pretty similar goal to Supabase. It gives you authentication, a database, file storage, functions, messaging, the usual suite.&lt;/p&gt;

&lt;p&gt;What sets it apart is that it's really built with self hosting in mind from the start. If the idea of running your own backend infrastructure instead of leaning on someone else's managed cloud appeals to you, Appwrite is worth a proper look.&lt;/p&gt;

&lt;h2&gt;
  
  
  And PocketBase
&lt;/h2&gt;

&lt;p&gt;PocketBase is a much smaller, lighter animal compared to Supabase or Firebase. Under the hood it's running on SQLite, which is itself a relational SQL database, and it pairs that with the handy stuff like auth and file storage.&lt;/p&gt;

&lt;p&gt;Its whole setup is refreshingly simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PocketBase

├── SQLite
├── Authentication
├── File Storage
└── Dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because it's so lightweight, PocketBase has become a favorite for quick prototypes, demos, and smaller side projects. It's just not usually what people reach for when they're building something that needs to scale up seriously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then what exactly is Neon
&lt;/h2&gt;

&lt;p&gt;Compared to everything above, Neon is honestly refreshingly simple to explain. Neon is basically managed PostgreSQL. That's genuinely it, nothing more hidden underneath.&lt;/p&gt;

&lt;p&gt;So if someone tells you they're using Neon, all that really means is their PostgreSQL database is being hosted and managed by Neon. There's no built in auth system, no storage service, no bundled backend platform sitting alongside it. Just the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application

↓

Neon

↓

PostgreSQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's exactly why a lot of developers pair Neon with something else on top, like Prisma, Drizzle, Clerk, Better Auth, or their own setup on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Laying them all out side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Extra Backend Services&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firebase&lt;/td&gt;
&lt;td&gt;Firestore&lt;/td&gt;
&lt;td&gt;NoSQL&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Appwrite&lt;/td&gt;
&lt;td&gt;SQL based database support&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PocketBase&lt;/td&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neon&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look closely and the pattern is obvious. Neon is the only one that's really just about hosting the database itself. Everyone else on that list gives you a whole backend ecosystem wrapped around one.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one should a beginner actually go with
&lt;/h2&gt;

&lt;p&gt;Don't pick based on whatever's trending on YouTube this month, that's honestly how a lot of people end up confused in the first place. Pick based on what you're actually trying to learn.&lt;/p&gt;

&lt;p&gt;If you want to genuinely understand relational databases, plain PostgreSQL is a solid starting point. If you want authentication, storage, and a dashboard without burning days configuring everything yourself, Supabase is a great pick. If you're building mobile apps and want tight integration with Google's ecosystem, Firebase is the logical choice. If you're just messing around with side projects or prototypes, PocketBase is genuinely convenient. And if owning your own infrastructure matters to you, Appwrite is worth exploring properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistake almost everyone makes early on
&lt;/h2&gt;

&lt;p&gt;A lot of people end up comparing PostgreSQL directly with Supabase, and honestly that comparison just doesn't hold up. It's a bit like comparing an engine to an entire car.&lt;/p&gt;

&lt;p&gt;The comparisons that actually make sense look more like this. PostgreSQL against Firestore. Or Supabase against Firebase. One of those is a database versus database comparison, the other is a platform versus platform comparison. Once that distinction clicks, a huge chunk of the confusion just disappears on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Whenever some new backend tool crosses your radar, there's really just one question worth asking before anything else. Is this actually a database, or is it a platform built around one?&lt;/p&gt;

&lt;p&gt;That single question quietly untangles most backend architecture confusion. Once you know exactly what each piece of the puzzle is actually responsible for, choosing between tools stops feeling like a random guessing game and starts feeling a lot more deliberate.&lt;/p&gt;

&lt;p&gt;Next time, I want to go one level up from the database itself and tackle another question beginners run into constantly, what exactly is an ORM, and why do people reach for tools like Prisma or Drizzle instead of just writing raw SQL themselves?&lt;/p&gt;

</description>
      <category>sql</category>
      <category>supabase</category>
      <category>appwritehack</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
