prisma dev, PGlite, and the one-connection ceiling
Prisma shipped prisma dev in 2025, and the pitch is one I have made myself: you should not need Docker Desktop, a docker-compose.yml, and a 400 MB image pull to get a Postgres on localhost. Run one command, get a database, write code. No containers, no config files, no login.
They are right. That is the correct problem to attack, and the thing they built to attack it is genuinely good engineering. prisma dev runs a local Prisma Postgres, which is PGlite underneath: real Postgres compiled to WebAssembly, packaged as a TypeScript library, under 3 MB gzipped. Not a Postgres emulator, not SQLite wearing a costume. Postgres, in WASM, running inside your Node process. PGlite has more than 15,000 stars on GitHub and millions of weekly downloads on npm, and it is under active development. If you have not looked at it, it is worth an afternoon regardless of what you end up shipping with.
I want to be specific about where it stops, because that boundary is documented, it is deliberate, and it is the whole reason this post exists.
One connection at a time
From Prisma's own local development docs:
The local Prisma Postgres database server accepts one connection at a time. Additional connection attempts queue until the active connection closes.
PGlite's docs say the same thing from the library side: PGlite "only has a single exclusive connection to the database." That is not a bug and it is not laziness. PGlite is Postgres compiled into a single WASM process. Real Postgres forks a backend process per connection; WASM has no fork model to give it. One process, one connection, and everything else waits its turn.
For a lot of local development that is fine. It stays fine right up until the moment your app is not the only thing that wants the database.
Here is the shape of that moment. You have next dev running, holding the connection through Prisma Client. In a second terminal you want to open psql to look at a row, and it sits there. Or you add a background worker to the project, a queue consumer or a cron script, and start it alongside the web app. Both processes want a connection. One gets it. The other blocks until the first one lets go, which for a long-lived dev server is "not until you kill it."
You did not do anything wrong. Two processes and one database is not an exotic architecture, it is Tuesday. But it is past the line where an embedded single-connection Postgres works, and the failure mode is confusing the first time you hit it, because nothing errors. It just hangs.
And it is one engine
The other boundary is quieter. prisma dev gives you Postgres. That is all it is trying to give you, and for a lot of projects Postgres is the whole database layer.
For a lot of others it is not. The stack drifts the way stacks drift: Postgres, then a cache once response times get annoying, then a vector store when the AI feature lands, then something for search that is better than ILIKE '%query%'. I wrote about what this costs you in production in The Multi-Database Tax. Locally it costs you something different, which is that your "no Docker" setup lasts exactly as long as your project is one Postgres. The second engine arrives and you are back to writing a compose file, except now you are running Docker for the cache and PGlite for the database, and your local environment is two systems instead of one.
There is a version of this argument that is unfair to Prisma, and I do not want to make it. PGlite is a library. prisma dev wraps that library in a nice CLI and couples it to the Prisma ORM, which is a completely reasonable product decision when 15 million weekly npm installs of your ORM are the audience. Nobody promised you a cache.
The same idea, native binaries
What I want locally is the prisma dev experience with the ceiling moved: no Docker, one command, but a real Postgres server process that takes as many connections as I open, and the rest of the stack available from the same tool.
That is what the Layerbase CLI does. It downloads and runs actual database binaries on your machine. Not containers, not a VM, not WASM. The Postgres that starts is the same Postgres that runs in production, with the same process model, the same pg_hba.conf, the same connection behavior.
npm i -g layerbaseThen create the database:
lbase create appdb -e postgresql --startFirst run downloads the binary for your platform and initializes the cluster, which takes a few seconds. After that it is cached and startup is close to instant.
lbase url appdbpostgresql://postgres@127.0.0.1:5432/appdbNow open psql in one terminal, run your dev server in another, and start a worker in a third. All three connect. That is the entire difference, and it is the reason to bother.
Add the cache while you are here:
lbase create cache -e valkey --start
lbase url cacheredis://127.0.0.1:6379/0Two engines, two commands, no YAML. The CLI covers 21 engines this way, so when the vector store or the analytics database shows up later it is the same verb again with a different -e.
Managing them is the small set of commands you would guess:
lbase list # everything you have created, and its status
lbase connect appdb # drops you into psql
lbase stop appdb # data persists
lbase start appdbKeep using Prisma
None of this is an argument against Prisma the ORM. Prisma is excellent, and pointing it at a real Postgres is a one-line change:
# .env
DATABASE_URL="postgresql://postgres@127.0.0.1:5432/appdb"// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}Everything you already do keeps working. prisma migrate dev applies your migrations. prisma studio opens against the same database. Prisma Client generates the same types. The only thing that changed is that the server on the other end of the socket is a native Postgres process instead of a WASM one, which means your migrations run against the thing that will run them in production, and prisma studio can be open at the same time as your app.
When prisma dev is the right call
If your project is one Postgres, one process, and you are already all-in on Prisma, prisma dev is a very good answer and I would not talk you out of it. Zero install beyond the ORM you already have, and the persistence mode is configurable if you want a clean database every run. For a single-service API or a small Next.js app with no worker, the one-connection limit may never come up.
PGlite is also the better tool for a category the Layerbase CLI does not touch at all: Postgres in the browser, Postgres inside a test file with no server to manage, Postgres embedded in an Electron app or an edge runtime. Nothing running native binaries competes with that. Different tool, different job.
The switch happens when a second thing needs the database, or when a second database needs to exist.
When the prototype grows up
Local is local. At some point you want the same stack somewhere your teammates and your preview deployments can reach, and the answer is not to run your laptop as a server.
Layerbase Cloud hosts 18 engines on one account and one bill. The free tier is $0 with no card, and idle databases sleep and wake when you reconnect instead of billing you for existing. Pro is $15/month flat, with no compute-hour meter, no per-command charge, and no per-search fee. Your connection string changes. Your Prisma schema does not.
# local
DATABASE_URL="postgresql://postgres@127.0.0.1:5432/appdb"
# cloud
DATABASE_URL="postgresql://layerbase:<password>@your-host.cloud.layerbase.dev:5432/appdb?sslmode=require"Prisma was right that local Postgres should not require Docker. The part I would add is that local Postgres should also not require you to have exactly one of them, running exactly one process, forever.
Keep reading
- Migrating a Railway database to LayerbaseRailway is a great place to ship an app and a usage-metered place to keep a database. Here is how to move your Railway Postgres, MySQL, or Redis to flat-priced managed Layerbase with one token.
- Every Free Database Tier That Sleeps, Pauses, or Expires - and What Staying Awake Actually CostsA database that scale-to-zeros after five minutes, a project that pauses after a week and needs a human to click Resume, and a database that gets deleted 44 days after you created it are three different products. Here is which vendor does which, and what the cheapest always-on version costs.
- A Testcontainers Alternative for the Database HalfTestcontainers is excellent, and its one hard requirement is a Docker-API compatible runtime. If the only thing your tests need is a real database, you can get the same throwaway instance without a container runtime at all.
- DBngin alternatives for when you need a terminalDBngin starts a local Postgres in one click and asks nothing of you, which is why it keeps showing up as the answer to running databases without Docker. The ceiling is the shape of the app: no command line, so nothing it does can be scripted, checked into a repo, or run on a CI machine.