[Improving Javascript package] Rewriting Prisma ORM - part 1
What is the cost of Prisma's great developer experience ?
Prisma is loved by many javascript developers thanks to its great developer experience. It provides an abstract and intuitive syntax to query your data from your backend and works out of the box with many SQL and No-SQL databases. It also generates a type-safe client to use in your code and allows you to run migrations easily.
But if it's so great, why do we need to rebuild it?
The problem with Prisma ORM
Recently I saw a youtube video from Codedamn about Prisma. Their company was switching from MongoDB to PlanetScale (MySQL) as a database and from Mongoose to Prisma as an ORM and discovered a few things.
In this case, they are running their backend in AWS Lambda, a serverless environment. This means two things :
Lambda functions should be lightweight and use low memory since both of them affect billing and performance
Lambda functions have a cold start where they copy your code to the runner, start Node.js and run your code.
Serverless comes with lots of advantages and is rising these days. But Prisma has a few inconveniences making it a bad choice for serverless.
The Query Engine
When you use your Prisma client to communicate with your database, your javascript code doesn't send anything to your database. Your client calls another binary that converts your javascript calls to SQL queries, the Query Engine. Prisma's Query Engine is written in Rust and runs in a different process.
This pattern is not bad, lots of Node.js packages use binding to binaries written in low-level languages like C or C++. The problem is that this Rust binding and the generated client weigh around 17MB which is large for a single library in a lambda function. While Prisma isn't the largest (Sequelize is about 22MB) it is far from Drizzle (another ORM weighting 2.4MB) and even further from the 900KB of PG, the most popular javascript PostgreSQL query client that processes raw SQL.
For the curious ones, here is how I measured the production size
npm init
, install the package (i.e npm install pg
), delete the node_modules
, then install the dependencies with npm i --omit=dev
to mimic the way we install dependencies in production. There were extra steps for Prisma as I installed only @prisma/client
then created a Prisma schema with a simple model and generated the client with npx prisma generate
.What are we gonna do?
In this series of articles, we'll build an ORM with Typescript that exposes the same API as Prisma. We'll focus on a single database type, PostgreSQL and thus rely on the PG lib. Then we'll create our schema file and finally dive into migrations and introspection.
We'll focus on having the smallest library and keep in mind that it will run on a serverless environment. In the end, we'll also know if there is a performance loss in dropping the Rust engine.
We'll start coding in the next article in this series. See you there ๐