Postgres vs SQLite vs Supabase: how I pick a database as a solo builder
This update was drafted on a schedule by the AI I build with, from real project notes — part of the vibecoding experiment this blog documents.
So here's the thing nobody tells you when you're building a lot of small products alone: the database decision isn't really a database decision. It's a decision about who gets paged at 2am when the thing falls over, and that someone is always me. Once you frame it that way, the choice between SQLite, a Postgres box I run myself, and a managed Postgres like Supabase stops being about benchmarks and starts being about how much operational weight I'm willing to carry for this particular app.
I did a backend version of this already — Next.js vs FastAPI — and the honest conclusion there was that the "right" answer is mostly about what you can supervise, not what's technically superior. The database question has the same shape. So let me just walk through how it actually plays out across what I've built, because the reasoning is clearer with real projects attached than in the abstract.
The default, more often than people expect, is SQLite — a single file on disk, no server, no connection pool, no network hop. App Marketing OS runs on it. It's a FastAPI app with Claude doing the work and SQLite underneath, and that's not a compromise, it's the correct call. The thing is a tool suite, the data is modest, and there is exactly one process touching it. The moment you don't have multiple writers fighting over the same rows across a network, a huge amount of the reason people reach for Postgres evaporates. SQLite is boring in the way I want infrastructure to be boring: it's just there, it doesn't have a status page, and there's no "did the database go down" failure mode because the database is a file sitting next to the code. The price you pay is real — concurrent writes are the weak spot, and it's not built for many app servers hitting one store at once — but for a single-operator tool, that price is usually zero because you never hit the ceiling.
Then there's the opposite end, which is Postgres I'm responsible for. ClipForge runs on Postgres, and that's deliberate — it's an engine designed to run unattended and post at volume across a lot of accounts, which means concurrent writes, background jobs, and the kind of relational querying where you actually want the grown-up database. This is the case SQLite isn't for. The catch, and it's the whole catch, is that "Postgres" is now a thing that exists on its own, with its own uptime, its own connection limits, its own "why is every query hanging" mysteries. I've been burned by exactly that class of problem — a stale connection string pointing at a host that quietly moved underneath me, and suddenly every query just hangs instead of failing loudly, which is somehow worse. That's the tax on running the real database: more power, and a new category of 2am.
In the middle, and honestly where a lot of my web apps land, is managed Postgres — Supabase for tab. It's still Postgres, so I get the real database with real concurrency and relational queries, but somebody else runs the box, handles the backups, and gives me auth and an API layer on top. For a shipped product with real users — tab. is a live iOS app with subscriptions and strangers' data in it — that managed layer is worth paying for, because the stuff it takes off my plate (backups, connection pooling, the auth I'd otherwise hand-roll badly) is exactly the stuff that's boring to build and catastrophic to get wrong. It is not free of failure modes. The free tier pauses a project after about a week of no traffic, and when it does, it's not a graceful degrade — it's a DNS-level disappearance that takes auth and everything else down with it, and it looks exactly like a certificate or network outage until you figure out what actually happened. Managed doesn't mean no-ops. It means a different ops, where the failures are someone else's architecture leaking through into your app.
So the actual decision tree in my head is short. Is there one process and modest data? SQLite, and don't apologize for it. Does this need to run unattended with lots of concurrent writes and I'm willing to own the box? Self-run Postgres. Is this a real product with real users where losing their data or hand-rolling auth would be a disaster? Managed Postgres, pay the money, and read the fine print on the free tier before you trust it with anything that matters. The relational-vs-not question barely enters into it, because for most of what I build the data is relational anyway — the honest variable is operational load, not data model.
What I try hardest not to do is pick the "serious" option as a flex. There's a pull, when you're building something you're proud of, to reach for the heavyweight database because it feels like what a real engineer would do. But every piece of standing infrastructure is a thing that can be down, a thing with a bill, a thing I have to remember exists six months from now when I've moved on to the next project and something starts failing. A single-operator shop can't afford infrastructure it chose for vanity. The SQLite file that never pages me is, a lot of the time, the more professional choice — it's just not the one that looks impressive in the stack list.
If I had to compress it to one line: don't pick the database, pick the failure mode you're willing to live with. SQLite's failure mode is a concurrency ceiling you probably won't hit. Self-run Postgres' is that you're now the DBA. Managed Postgres' is that you've traded your failures for someone else's, which is a good trade right up until their architecture surprises you. Knowing which of those three 2am calls you'd rather get is, genuinely, the whole decision.