# Top 5 Myths about Prisma ORM URL: https://www.prisma.io/blog/top-5-myths-about-prisma-orm Published: 2024-12-19 Authors: Nikolas Burk Tags: education, orm Description: Discover the truth behind five common misconceptions about Prisma ORM. In this article, we debunk the myths, explore their origins, and separate fact from fiction. Discover the truth behind five common misconceptions about Prisma ORM. In this article, we debunk the myths, explore their origins, and have a little fun separating fact from fiction. * [Myth 1: Prisma ORM is slow](#myth-1-prisma-orm-is-slow) * [Myth 2: You can't use low-level DB features](#myth-2-you-cant-use-low-level-db-features) * [Myth 3: Prisma ORM uses GraphQL under the hood](#myth-3-prisma-orm-uses-graphql-under-the-hood) * [Myth 4: Prisma Client must live in `node_modules`](#myth-4-prisma-client-must-live-in-node_modules) * [Myth 5: Prisma doesn't work well with Serverless/Edge](#myth-5-prisma-doesnt-work-well-with-serverlessedge) * [Help us make Prisma ORM the best DB library 💚](#help-us-make-prisma-orm-the-best-db-library-💚) ## Myth 1: Prisma ORM is slow [#myth-1-prisma-orm-is-slow] When we initially released [Prisma ORM for production](https://www.prisma.io/docs/orm/v6/overview/introduction/why-prisma) in 2021, we followed the *"Make it work, make it right, make it fast*" approach. This means the initial version of Prisma ORM hadn't been particularly optimized for speed. However, since then we have invested heavily into performance and have released performance improvements in almost every release. We also created open-source [ORM benchmarks](https://benchmarks.prisma.io/) comparing the three most popular ORMs in the TypeScript ecosystem and found that Prisma ORM's performance is similar to the others, sometimes even faster. ### Major performance improvements in almost every release [#major-performance-improvements-in-almost-every-release] Prisma ORM has been following a steady and reliable release cadence in cycles of three weeks. If you check out the [release page](https://github.com/prisma/orm/releases/) of the `prisma/prisma` repo, you'll notice that almost every release came with some kind of performance improvements — be it an optimization of a particular SQL query (as seen in, [5.11.0](https://github.com/prisma/orm/releases/tag/5.11.0), [5.9.0](https://github.com/prisma/orm/releases/tag/5.9.0), [5.7.0](https://github.com/prisma/orm/releases/tag/5.7.0), [5.4.0](https://github.com/prisma/orm/releases/tag/5.4.0), [5.2.0](https://github.com/prisma/orm/releases/tag/5.2.0), [5.1.0](https://github.com/prisma/orm/releases/tag/5.1.0), …), introducing new batch queries like `createManyAndReturn` (in [5.14.0](https://github.com/prisma/orm/releases/tag/5.14.0)), [speeding up cold starts by 9x](https://www.prisma.io/blog/prisma-and-serverless-73hbgKnZ6t) (in [5.0.0](https://github.com/prisma/orm/releases/tag/5.0.0)) or introducing [support for native JS-based drivers](https://www.prisma.io/blog/serverless-database-drivers-KML1ehXORxZV) (in [5.4.0](https://github.com/prisma/orm/releases/tag/5.4.0)). We are also working on rewriting the Rust-based Query Engine from Rust to TypeScript to save some overhead in serialization between language boundaries and are expecting notable performance improvements from this change as well. ### Prisma ORM lets you choose the best JOIN strategy [#prisma-orm-lets-you-choose-the-best-join-strategy] Another huge win for developers using Prisma ORM was the [ability to pick the best JOIN strategy](https://www.prisma.io/blog/prisma-6-better-performance-more-flexibility-and-type-safe-sql) for their relation queries. In principle, there are two different approaches when you need to query data from multiple tables that are related via *foreign keys*: #### Database-level: Using the `JOIN` keyword in a single query [#database-level-using-the-join-keyword-in-a-single-query] With this approach, you send a single query to the database using the SQL `JOIN` keyword and let the data be *joined* by the database directly: ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/aa38701684dfb2dcfc9308f698bada759477f88f-3200x2390.png) #### Application-level: Send multiple queries and join in application [#application-level-send-multiple-queries-and-join-in-application] When joining on the application-level, you send multiple queries to individual tables to the database and *join* the data yourself in your application: ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/8c960545b98a710c8856495120cba3e3d6dbc612-3200x2280.png) #### When to use which? [#when-to-use-which] Depending on your use case, dataset, schema, and several other factors, one strategy may be more performant than the other. The application-level joining method is also called *join decomposition* and often used in high-performance environments: > Many high-performance web sites use join decomposition. You can decompose a join by running multiple single-table queries instead of a multitable join, and then performing the join in the application. > > [High Performance MySQL, 2nd Edition](https://www.oreilly.com/library/view/high-performance-mysql/9780596101718/ch04.html#join_decomposition) | O'Reilly Up until Prisma ORM [5.7.0](https://github.com/prisma/orm/releases/tag/5.7.0), Prisma ORM would always use the application-level JOIN strategy. However, with the 5.7.0 release, we now allow you to pick the best JOIN strategy for your use case, ensuring you can always get the best performance for your queries. ### ORM benchmarks: No major performance differences [#orm-benchmarks-no-major-performance-differences] After all these improvements, we wanted to know where Prisma ORM stands in terms of performance in comparison to other ORM libraries. So, we created transparent [benchmarks](https://benchmarks.prisma.io/) comparing the query performance of TypeORM, Drizzle ORM and Prisma ORM. The benchmark repo is [open-source](https://github.com/prisma/orm-benchmarks) and we're inviting everyone to reproduce the results and share them with us. ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/2115069c1f42c6b5062f48c80167a50b66eac00d-2144x1912.png) So, what did the benchmarks show? TLDR: Based on the data we've collected, it's not possible to conclude that one ORM *always* performs better than the other. Instead, it depends on the respective query, dataset, schema, and the infrastructure on which the query is executed.. You can read more about the setup, methodology and results of the benchmarks here: [Performance Benchmarks: Comparing Query Latency across TypeScript ORMs & Databases](https://www.prisma.io/blog/performance-benchmarks-comparing-query-latency-across-typescript-orms-and-databases). ### Make your queries faster with Prisma Optimize [#make-your-queries-faster-with-prisma-optimize] One major insight from running the benchmarks was that it's possible to write fast and slow queries, regardless which tools you use. Meaning that in the end, a lot of the burden to ensure database queries are fast is actually on the developer themself. ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/acff3e3fd1fd16c0b9d6c0831613ee362b013881-1570x1215.gif) To ensure developers using Prisma ORM are making their queries as fast as possible, we recently launched [Prisma Optimize](https://www.prisma.io/optimize) — a tool that analyzes the queries you send to your database with Prisma ORM and gives you insights and recommendations for how to improve them. ## Myth 2: You can't use low-level DB features [#myth-2-you-cant-use-low-level-db-features] Prisma ORM—by nature of being an ORM—provides a higher-level abstraction over SQL in order to improve productivity, confidence and overall developer experience when working with databases. This higher-level abstraction manifests in the *human-readable* Prisma schema (to describe the structure of your database) and the *intuitive* Prisma Client API (for querying the database). However, given that an abstraction also sometimes make it impossible to access functionality of the underlying technology (in the case of Prisma ORM: a database), a proper escape hatch is needed to drop down to a lower level of abstraction. So, in order to not sacrifice important features that may be needed in more advanced scenarios or edge cases, Prisma ORM provides convenient fallbacks for developers to access the underlying functionality of the database. ### Customized migrations let developers use any SQL feature [#customized-migrations-let-developers-use-any-sql-feature] While it's not possible to represent *all* the features a database may have in the Prisma schema, you can still make use of these by [customizing the migration files](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/development-and-production#customizing-migrations) that are generated by Prisma Migrate. To do so, you can simply use the `--create-only` flag whenever you create a new migration and make edits to it before it's applied against the database. ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/25269e1341880f556defb4a52c3a593df68336b1-1047x1200.png) Using customized migrations, you can freely manipulate your database schema while ensuring that all changes are executed by Prisma Migrate and tracked in its [migration history](https://www.prisma.io/docs/orm/v7/prisma-migrate/understanding-prisma-migrate/migration-histories). ### Write type-safe SQL in Prisma ORM [#write-type-safe-sql-in-prisma-orm] When it comes to queries, there are two main ways how developers can drop down to raw SQL and write queries that can't be expressed using the higher-level query API. #### TypedSQL: Making raw SQL type-safe [#typedsql-making-raw-sql-type-safe] Prisma ORM now gives you the best of both worlds: A convenient high-level abstraction for the majority of queries and a flexible, type-safe escape hatch for raw SQL. [Watch the video on YouTube](https://www.youtube.com/watch?v=yyOM_fBMehA) Consider this example of a raw SQL query you may need to write in your application: ```sql -- prisma/sql/conversionByVariant.sql SELECT "variant", CAST("checked_out" AS FLOAT) / CAST("opened" AS FLOAT) AS "conversion" FROM ( SELECT "variant", COUNT(*) FILTER (WHERE "type"='PageOpened') AS "opened", COUNT(*) FILTER (WHERE "type"='CheckedOut') AS "checked_out" FROM "TrackingEvent" GROUP BY "variant" ) AS "counts" ORDER BY "conversion" DESC ``` After a generation step, you'll be able to use the `conversionByVariant` query via the new `$queryRawTyped` method in Prisma Client: ```ts import { PrismaClient } from '@prisma/client' import { conversionByVariant } from '@prisma/client/sql' // `result` is fully typed! const result = await prisma.$queryRawTyped(conversionByVariant()) ``` Learn more about this on our blog: [Announcing TypedSQL: Make your raw SQL queries type-safe with Prisma ORM](https://www.prisma.io/blog/announcing-typedsql-make-your-raw-sql-queries-type-safe-with-prisma-orm) #### Use the Kysely SQL query building extensions [#use-the-kysely--sql-query-building-extensions] Another alternative is to use the Prisma Client extensions for [Kysely](https://github.com/eoin-obrien/prisma-extension-kysely) which lets developers build SQL queries using its TypeScript API. For example, using the Kysely extension you can write SQL queries with Prisma as follows: ```ts const query = prisma.$kysely .selectFrom("User") .selectAll() .where("id", "=", id); // Thanks to kysely's magic, everything is type-safe! const result = await query.execute(); ``` This enables you to write advanced SQL queries without leaving TypeScript and Prisma ORM. > **Fun fact**: Kysely's core maintainer [Igal](https://x.com/prisma/status/1813559287316185573) recently joined our team at Prisma 😄 ## Myth 3: Prisma ORM uses GraphQL under the hood [#myth-3-prisma-orm-uses-graphql-under-the-hood] Depending on how long you've been around in the Prisma community, this may surprise you: Prisma used to be a GraphQL Backend-as-a-Service provider called [Graphcool](https://www.graph.cool/): ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/fc9995d3f9b880ad6ea35cf1b4a29fa1cefb5df5-1360x851.png) In 2018, Graphcool [rebranded to Prisma](https://www.prisma.io/blog/prisma-raises-4-5m-to-build-the-graphql-data-layer-for-all-databases-663484df0f60) and climbed down the "abstraction ladder" from the API layer to the database. The first version of Prisma (before it became an ORM), was a CRUD GraphQL layer *between* your API server and database: ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/5f7e0d66d047c7f0f44fc853065ae7f18ca68b85-1480x264.png) At this point, the main value that Prisma 1 provided was the convenient data modeling, migrations querying which were all done via GraphQL. In order to simplify usage of Prisma and avoid requiring users to set up and maintain an entirely separate server, we rewrote Prisma's GraphQL engine in Rust, making it available as a binary downloadable via `npm install`: ![](https://www.prisma.io/blog/top-5-myths-about-prisma-orm/imgs/32a81d2c9ce4bc1f989064c54bc0d8870f8f2e75-1480x264.png) The Query Engine was running a GraphQL server as a side-car process on the application server. Developers were interacting with it using Prisma Client and writing queries TypeScript. This was the initial architecture of Prisma ORM. Since then, we have made countless optimizations to the architecture. Most notably, we introduced [N-API](https://nodejs.org/api/n-api.html) for the communication between Rust and TypeScript, replaced GraphQL with a custom, [JSON-based wire protocol](https://www.prisma.io/blog/prisma-and-serverless-73hbgKnZ6t#a-new-json-based-wire-protocol), enabled usage of [JS-native database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) and a lot more! Today, there's no residue of GraphQL in Prisma ORM any more — and we're not stopping here either, we keep improving the architecture of Prisma ORM. Our next step is to move the Query Engine that does the heavy-lifting of generating SQL from Rust to TypeScript and make Prisma ORM even more efficient. ## Myth 4: Prisma Client must live in `node_modules` [#myth-4-prisma-client-must-live-in-node_modules] A common misconception developers have about Prisma ORM is that the generated Prisma Client library *must* live in `node_modules`. However, `node_modules` is just the *default* location to provide a familiar developer experience and enable simple imports: ```ts // When Prisma Client is in `node_modules`: import { PrismaClient } from "@prisma/client"; ``` That location can be easily customized by providing a custom `output` path on the `generator` block: ```ts generator client { provider = "prisma-client-js" output = "../src/generated/client" } ``` In that case, you need to adjust the `import` statements and import Prisma Client from your file system. Considering the example above, the `import` would now look like this: ```ts // When Prisma Client is in `./generated/client`: import { PrismaClient } from "./generated/client"; ``` This can be really useful when you are working in a monorepo or other special environment where generating Prisma Client into `node_modules` may cause problems. ## Myth 5: Prisma doesn't work well with Serverless/Edge [#myth-5-prisma-doesnt-work-well-with-serverlessedge] When Prisma ORM was designed, Serverless and Edge deployments still were early and emerging technologies. Since then, they have become a popular deployment model that a lot of development teams rely on. The initial architecture of Prisma ORM, with the Query Engine binary and the internal GraphQL server, wasn't optimized for Serverless environments and there were numerous problems: * Slow cold starts due to the GraphQL-based wire protocol. * No ability to use Serverless Drivers of modern DB providers (like Neon and PlanetScale); this entirely prevented usage of Prisma Client at the Edge. * Large bundle size due to Query Engine binary. * Added complexity by needing to declare `binaryTargets` if the local machine differed from the target machine. We have recognized all of these problems and, over time, have implemented solutions and drastically improved the DX of Prisma ORM in Serverless environments: * The cold starts aren't a problem any more since we [removed GraphQL](https://www.notion.so/Misconceptions-about-Prisma-ORM-1599e8aecef7806caa15d313ea90d820?pvs=21) from the Query Engine internals and [sped up cold starts by 9x](https://www.prisma.io/blog/prisma-and-serverless-73hbgKnZ6t). * Serverless and other [JS-native database drivers](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/database-drivers) (like `pg`) can now be used with Prisma ORM thanks to driver adapters. * We have reduced the bundle size of Prisma ORM to less than 1MB, making it possible to use it in the free plans of major Edge function providers (like Cloudflare, who have a 3MB limit for their free plans). * … and we are working on further improvements: The move from Rust to TypeScript will remove the need to declare `binaryTargets` and overall make the deployment of Prisma ORM a lot more smooth than it ever was. ## Help us make Prisma ORM the best DB library 💚 [#help-us-make-prisma-orm-the-best-db-library-] At Prisma, we strongly value the feedback we receive from our community! While some of the misconceptions floating around about Prisma ORM may have been true in the past, we heard our users and have been hard at work to improve the situations around them. > If you're curious to learn more about our approach to open-source governance, check out the [Prisma ORM Manifesto](https://www.prisma.io/blog/prisma-orm-manifesto). We are going to continue our efforts to make Prisma ORM the most performant database library with the best possible DX in the TypeScript ecosystem. Let us know via [GitHub](https://github.com/prisma/orm), [Discord](https://pris.ly/discord) or [X](https://pris.ly/x) what other improvements you like to see 🙌 If you're excited about Prisma ORM, you can help us clarify these misconceptions by sharing this post whenever you see some of them pop up in the developer community. Also, if there are any more myths you'd like us to bust, [tell us](https://x.com/intent/post?text=hey+%40prisma%2C+bust+this+myth%21+%F0%9F%94%A8%0a%3Cshare+details+the+myth%3E)!