# SQLite vs Mongo vs Supabase: 2 Triggers End the Debate

> Latency, cost, limits, and the two triggers that say switch. Plus the one-var escape hatch that makes it free.

Source: https://boringpush.com/blog/sqlite-vs-mongodb-vs-supabase-nextjs

## The most rewritten decision in SaaS

"Which database?" generates more rewrites than any other early choice. Start Postgres, pay rent through zero revenue, fight connection pools at the first spike.

Start Mongo, hand-roll relations you actually needed. Start SQLite, get told it "doesn't scale" by people running 200 users.

The threads agree on the pain and disagree on everything else — because the right answer is temporal: different databases at different revenues, and the switching cost is the whole game.

## The table: all three, no romance

| Axis | SQLite (WAL, NVMe) | MongoDB (Atlas) | Supabase (Postgres) |
|---|---|---|---|
| Read latency | 0.1ms local | 5–35ms network | 5–35ms network |
| Cost at start | $0 (rides the VPS) | Free tier → $9+/mo | Free tier → $25+/mo |
| Cost at scale | $0 until one box ends | Grows with ops + storage | Grows with compute + bandwidth |
| Relations | JOINs, FKs (real SQL) | Embedded docs (denormalize!) | JOINs, FKs, RLS policies |
| Connection limits | None (file descriptor) | Pooled (watch serverless) | Pooled (Supavisor helps) |
| Killer feature | Zero ops, instant | Flexible schema evolution | Auth + realtime + RLS built in |
| Killer risk | One-box ceiling | Relation modeling debt | Bill + lock-in creep |
| Switch trigger | — (start here) | Document-shaped data + Atlas elsewhere | RLS/realtime needed, or write contention |

![SQLite one file, WAL, and the exit](/blog/sqlite-prod-playbook/one-file-wal-and-the-exit.svg "Start on the file, leave by variable: the two triggers are the only exit signs.")

Two triggers say switch, and only these two: sustained write contention (`busy_timeout` errors — readers never trigger it), or a Postgres-only feature you actually use (RLS policies, realtime channels). Everything else — "we might need scale," "investors expect Postgres," "the tutorial used Prisma" — is vibes with a price tag.

Most SaaS never hits trigger one; trigger two is a product decision, not an infrastructure emergency. Try it yourself:

```widget db-switch show=sqlite
```

The BoringPush escape hatch makes both triggers cheap: identical behavior and field shapes across all three engines, so switching is one database setting plus keys — zero query rewrites, same routes, same paywall guards. Start SQLite, earn the switch, change a setting on a calm Tuesday.

Ship from anywhere on a Next.js stack where the database is a deployment detail instead of a migration project.

## FAQ

### Is MongoDB "webscale" and SQLite "toy"? (No.)

Both myths. Mongo scales via sharding you'd rarely need; SQLite serves 100k+ ops/sec locally.

Scale is about access patterns and indexes, not logos.

### What about Prisma/Drizzle instead of raw parity?

ORMs add a migration-framework dependency and a query-builder dialect to every switch. Raw + identical function names keeps the escape hatch one variable wide.

Fewer layers, fewer 2am surprises.

### Do I need connection pooling on SQLite?

No pool exists — that's the feature. One writer serialized via `BEGIN IMMEDIATE`, readers in parallel.

Pool exhaustion, the classic serverless outage, is structurally impossible.

### Supabase vs raw Postgres?

Supabase buys auth/realtime/storage/dashboard in one bill; raw Postgres (RDS/self-hosted) buys control. If you want the ecosystem, Supabase; if you want the minimum, a bigger VPS with Postgres.

BoringPush speaks both.

### Can I run two at once (SQLite prod + Supabase analytics)?

Yes — and it's recommended: product reads stay 0.1ms local while heavy aggregations run against the warehouse. Separate files, separate fates.
