# prisma dev, PGlite, and the one-connection ceiling

> prisma dev runs a local Postgres on PGlite with no Docker and no config, and it is right about the problem it picked. It also takes one connection at a time and only speaks Postgres. Here is what to run when your stack needs more than that.

Published: 2026-07-30
Canonical: https://layerbase.com/blog/prisma-dev-alternative

Short version: `prisma dev` is a good answer as long as your project is one Postgres and one process. It runs on PGlite, which is Postgres compiled to WebAssembly, and a WASM process has no fork model, so it accepts exactly one connection at a time. The second thing that wants the database, a background worker or a `psql` session next to your dev server, does not error. It waits. If you need a second connection or a second engine, run a real Postgres binary locally instead: same no-Docker, one-command experience, without either 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](https://www.prisma.io/docs/local-development/postgres), which is [PGlite](https://pglite.dev) 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](/blog/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.

|                   | prisma dev                                                   | Layerbase CLI                                               |
| ----------------- | ------------------------------------------------------------ | ----------------------------------------------------------- |
| **What runs**     | PGlite: Postgres compiled to WebAssembly, under 3 MB gzipped | The real engine binary for your platform                    |
| **Connections**   | One at a time, the rest queue                                | As many as you open                                         |
| **Engines**       | PostgreSQL                                                   | over 20 engines                                             |
| **Docker**        | Not required                                                 | Not required                                                |
| **Prisma ORM**    | Coupled to it                                                | Works with it, over `DATABASE_URL`                          |
| **Embeddable**    | Yes: browser, test file, Electron, edge runtime              | No, it is a server process                                  |
| **Process model** | One WASM process                                             | Postgres forking a backend per connection, as in production |

That is what the [Layerbase CLI](https://layerbase.com/docs/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.

```bash
npm i -g layerbase
```

Then create the database:

```bash
lbase create appdb -e postgresql --start
```

First 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.

```bash
lbase url appdb
```

```text
postgresql://postgres@127.0.0.1:5432/appdb
```

Now 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:

```bash
lbase create cache -e valkey --start
lbase url cache
```

```text
redis://127.0.0.1:6379/0
```

Two engines, two commands, no YAML. The CLI covers over 20 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:

```bash
lbase list           # everything you have created, and its status
lbase connect appdb  # drops you into psql
lbase stop appdb     # data persists
lbase start appdb
```

## Keep 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:

```bash
# .env
DATABASE_URL="postgresql://postgres@127.0.0.1:5432/appdb"
```

```prisma
// 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.

## FAQ

### Why does psql hang when prisma dev is running?

Because the connection is already taken. The local Prisma Postgres server accepts one connection at a time and queues the rest until the active one closes, and your dev server is holding it through Prisma Client. Nothing errors, which is what makes it confusing the first time. Kill the dev server and `psql` connects immediately.

### Can PGlite handle more than one connection?

No, and that is by design rather than an oversight. PGlite is Postgres compiled into a single WASM process, and WASM has no fork model, so it cannot spawn the per-connection backend process that a normal Postgres server does. Prisma's docs and PGlite's docs both say so plainly.

### Does prisma dev support MySQL, Redis, or anything besides Postgres?

Postgres only. That is all `prisma dev` set out to give you, and it is the right scope for a tool bundled with an ORM. The cost shows up later, when the cache or the vector store arrives and your no-Docker local setup becomes a compose file for the second engine plus PGlite for the first.

### Do I have to stop using Prisma to run a local Postgres binary?

Not at all. Point `DATABASE_URL` at the instance and everything you already do keeps working: `prisma migrate dev` applies migrations, `prisma studio` opens against the same database, and Prisma Client generates the same types. The only change is that the server on the other end of the socket is a native process, which means Studio and your app can be open at once.

### When is PGlite the better tool?

Whenever the database needs to be embedded rather than served. Postgres in the browser, Postgres inside a test file with no server to manage, Postgres shipped in an Electron app or an edge runtime: nothing running native binaries competes with that, and it is a category worth knowing about even if you host your dev database elsewhere.

## 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](https://cloud.layerbase.com/create) hosts 19 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.

```bash
# 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.
