Why shipping Prisma with our Electron app was a mistake

Why shipping Prisma with our Electron app was a mistake

When we made the move to Electron, I had to decide which database-technology we wanted to use. I’m a big fan of Prisma so I thought to myself: Can we not simply ship Prisma with Electron?

Turns out you can, but let me tell you why it wasn’t the best idea.

What is Prisma?

For those of you who don’t know, Prisma is an ORM that is able to generate a type-safe database client, tailored to your database schema. The way this works is pretty clever:

  • You define a database schema
  • Prisma then has a CLI to generate a client that is tailored towards the schema you defined

Pretty cool.

Importing this tailored client also provides a lot of context to your editor, so you can benefit from powerful autocomplete features.

For example, if you have a users table and you want to find a user with a matching E-mail address, your IDE will give you hints about what type the email column is.

Prisma also has the capability to handle migrations for you, so whenever you evolve your schema, you can generate a migration file and using Prisma Migrate, you can apply this migration to your database.

Setting up Prisma + Electron

Under the hood, Prisma uses engines that are written in Rust and expose a low-level interface for interacting with native API’s. Lucky for us, we don’t have to compile these engines ourselves, but Prisma provides precompiled engines for every major OS.

In a normal situation, Prisma runs on a server, for example in an Authentication service.

Because we wanted to power our offline-first Electron-app with Prisma, we had to figure out how we can ship 2 major core engines to the client:

  1. The query engine, responsible for querying the database
  2. The migration engine, responsbile for handling migrations

Both of these engines have a massive footprint of over 30MB each, adding a whopping 60MB to our binary.

Electron is not exactly known for its lean app size, so adding an additional 60MB of overhead is not exactly ideal.

On top of that, Prisma needs the Microsoft Visual C++ runtime components to be installed. Our POS hardware came with Windows, but did not come with these components preinstalled, so we had to modify our installer to check whether or not this had to be downloaded & installed, adding additional complexity.

Our merchants aren’t known for their tech savviness, which often meant that they had an internet subscription from a lower-tier ISP. Long story short - download speeds were a disaster, so shipping an Electron app of around 150MB is a challenge.

I do my development on a mac, but because Prisma required OS-specific bindings, we had to set up a Windows-based Github action, with its own quirks and challenges.

Working with prisma

Once we figured out how to ship the necessary engines with our Electron app, we achieved a milestone: Prisma was working inside our Electron app.

The next challenge was figuring out how to evolve our schema in the field, because with every update we were planning to introduce new features, which often required changes to the database.

In a normal situation you’d run something like npx prisma migrate deploy - but since we were operating within an Electron context, we had to do things a bit differently.

On every app startup, we had to do a sequence of steps:

  • we had to find the location of the prisma client library
  • we had to find the location of the query and migration engine and the schema.prisma file on the file system
    • This all lived inside the app executable
  • we then had to fork a new node process, passing in the necessary environment variables (eg. the database path)
  • this forked process, could then run prisma migrate deploy --schema {path}

This was quite the hassle to set up, but once it was working it did its job well. On every startup this command was executed, and the database was brought up-to-date.

The thing we had to keep in mind was that the user did not necessarily install every single app update we pushed out. This meant that a user could jump from v 1.0 to 1.5.

This adds an extra challenge when shipping migrations, because you don’t want to end up in a situation where a migration fails on app startup.

Downsides

We now had an app that shipped Prisma and was able to do queries and migrations. Even though this worked, the impact on the overall app startup speed is a disaster. Once the app is booted up however, the runtime performance was not affected too much.

We ran this setup a little over 1 year in production before we decided to abandon it and migrate to a nosql setup using IndexedDB. If you’re thinking about shipping prisma with Electron, I would highly recommend you reconsider, no matter how tempting it is. Instead, take a look at alternatives like RxDB for example.

The downsides of shipping Prisma in our Electron app greatly outweighed the upsides and ultimately slowed down our development, as we spent too much time fighting against this setup instead of building new features.

I hope you learn from my mistakes, and I will see you in the next!

Further reading

Using Prisma with the Electron Framework · Issue #9613 · prisma/prisma
Prisma Support for Electron Electron is a framework for building cross-platform desktop apps with JavaScript, HTML, and CSS. While Electron can use similar frameworks and tooling as web application…

Subscribe to sabatino.dev

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe