Why I Stopped Using Supabase
I shipped four projects on Supabase between 2023 and 2025. It was the right choice every time. By early 2026 I had moved all of them off, and every new project starts on a self-hosted Postgres on a $12 Hetzner box. This isn't a hit piece—Supabase is genuinely great software. It's a story about what happens when your needs and your tools drift apart.
What Supabase Got Right
Credit where it's due. Supabase made three things easy that used to be painful:
- Auth — email, magic links, OAuth providers, RLS-based authorization, all in 30 minutes
- Realtime — postgres triggers + websockets, working out of the box
- Storage — S3-compatible bucket with auth-integrated policies
For a solo dev or a small team in 2023, this stack saved you weeks. It's the reason every YC batch from 2022 to 2024 had a Supabase logo somewhere in the architecture diagram.
Where It Started Hurting
The cracks I hit, in roughly the order I hit them:
1. Row Level Security is a beautiful trap. RLS policies in plain SQL look elegant in the docs. In production, with a real schema, they become a debugging nightmare. Policy interactions are non-obvious. Performance regressions are silent. The query that worked in staging fails in prod because the user has a different role. By project three I was writing an entire test suite just to assert RLS behavior—which is a sign the abstraction is wrong.
2. Pricing scales weirdly. The free tier is generous. The Pro tier is reasonable. The jump after that is brutal. Egress, compute add-ons, branching, and the "you exceeded your daily DB CPU" emails added up to numbers I would never have agreed to upfront.
3. Connection pooling is its own product. PgBouncer in transaction mode breaks prepared statements. Session mode breaks scaling. Supavisor was supposed to solve it. It mostly does, except when it doesn't, and when it doesn't you can't see why because the dashboards are limited.
4. The vendor-flavored Postgres surprises you. Supabase ships a heavily extended Postgres with auth schema, storage schema, realtime schema, and a wall of triggers and functions. Most of the time you don't notice. When you do, you're trying to debug why a pg_dump doesn't restore cleanly into vanilla Postgres.
5. The 2 AM problem. Twice in a 14-month period I got a maintenance email that my project would be migrated, and twice the migration produced a brief outage I couldn't predict or work around. That's fine for a side project. It's not fine for a paying customer's data.
What I Use Now
The current stack on every new project:
- Hetzner CX22 at $4/month — 2 vCPU, 4 GB RAM, 40 GB SSD. Plenty for the first 100k users.
- Vanilla Postgres 17 in Docker, with
pg_basebackupto a second Hetzner box for replication - Drizzle ORM for schema and queries—type-safe, migration-aware, works with raw SQL when needed
- Lucia / Auth.js / hand-rolled for auth depending on complexity
- MinIO / RustFS for S3-compatible storage on the same box
- Caddy in front for TLS, with
tailscalefor admin access pg_cron+pg_dumpto a Backblaze B2 bucket for backups, $0.005/GB/month
Total fixed monthly cost: about $12 including backups. Variable cost: nothing meaningful. The whole stack fits in a docker-compose.yml I copy between projects.
What This Costs Me
Honest accounting: this is more work than Supabase. Specifically:
- Auth — about 4 hours of setup vs. 30 minutes
- Realtime — Postgres
LISTEN/NOTIFY+ a small websocket server, about 1 day to write, reusable forever - Storage — MinIO setup is 30 minutes, but auth-integrated policies are mine to write
- Monitoring —
pg_stat_statements+ a Grafana dashboard, about 2 hours
Call it a one-time tax of two days, then near-zero recurring cost. Compared to the recurring cost of Supabase surprises and pricing tier jumps, it's paid back inside three months on any project that has paying users.
When Supabase Is Still The Right Call
I will absolutely still recommend Supabase to people in three situations:
- Pre-product-market-fit prototypes. If you don't know whether you'll have users in two months, don't run your own Postgres.
- Teams without backend depth. If nobody on the team has run Postgres in production before, the operational risk of self-hosting is real and Supabase is the right hedge.
- Heavy realtime workloads. Their realtime infrastructure is good and rebuilding it from scratch is a lot of work.
Outside those, the math has flipped. Postgres is rock-solid. Hetzner is cheap. Drizzle and Hono make the boilerplate trivial. The DIY stack costs about $12/month, has zero surprise migrations, and produces a SQL dump that restores into vanilla Postgres anywhere.
The Bigger Pattern
Every "we made the boring infrastructure easy" SaaS has the same trajectory: indispensable in year one, friction in year three, replaced by year five. The friction comes from the abstractions that made it easy in the first place. RLS, vendored Postgres, custom auth schemas—these are gifts that become debts.
The boring stack underneath is still here. Postgres, Linux, Caddy, Docker. Cheaper than ever, more reliable than ever, and the LLM that's writing your docker-compose.yml already knows all of it.
When the abstraction starts surprising you, that's the signal. The substrate is right there.