sunmoon.dev
All writing

The Next.js + Supabase Stack I Use to Ship SaaS Fast

Seunghun Lee
SaaSNext.jsSupabaseengineering

Most "what stack should I use" debates die because they're answered in the abstract. People argue about frameworks they've never run a payroll on. I'm answering this one differently: this is the stack I actually ship and operate my own products with, the one that pays my bills, the one I get paged about at 2am. No theory.

If you're a founder or a small team trying to get a real SaaS to revenue without drowning in infrastructure, here's the stack I reach for and, more importantly, why each piece earns its place.

The problem isn't the framework — it's the operating cost

Picking a stack feels like a one-time decision. It isn't. Every choice you make on day one becomes a tax you pay every single day after: more services to monitor, more glue code to maintain, more bills to reconcile, more ways for a 2am page to find you.

I learned the weight of operational cost the expensive way. At Spotify and Klarna I watched how much engineering effort goes into keeping things running versus building new things. At a Y Combinator–backed startup I learned the opposite lesson — that a tiny team has to ruthlessly avoid anything that doesn't directly move the product forward. Both of my own products, transcribe.so and goodlisten.co, run on the stack below precisely because it keeps that daily operating cost low enough that I can build instead of babysit.

So my filter for every layer is the same: does this reduce the number of things I have to operate, without locking me into a corner I can't get out of?

The stack, layer by layer

Here's the whole thing in one view, then I'll defend each line.

Layer What I use Why
Framework Next.js (App Router) One codebase for UI + API, server components, great deploy story
Database Postgres via Supabase Real SQL, not a proprietary store you can't leave
Auth Supabase Auth RLS-backed, integrated with the DB, no separate identity vendor
Billing Stripe The default for a reason; webhooks are the source of truth
Hosting Vercel or a VPS Start managed, move to a box when the math changes
Background work Postgres queue or a worker fleet Boring, observable, no extra broker until you need one

Next.js App Router: one codebase, two jobs

The App Router collapses the frontend/backend split that used to cost a small team a second repo, a second deploy pipeline, and a second set of types. Server components fetch data where the data lives, route handlers give me an API when I need one, and I ship the whole thing as a unit.

The thing I value most isn't a feature — it's that the boundary between "this runs on the server" and "this runs in the browser" is explicit. When you're operating a product alone, knowing exactly where your code executes is worth more than any clever abstraction.

Postgres via Supabase: the part that matters most

This is the layer I'm most opinionated about, and it's where my former Supabase Expert Partner perspective comes in. The single most important property of your database is whether you can leave it.

Supabase is Postgres. Not "Postgres-compatible," not "Postgres-inspired" — actual Postgres with a connection string. That means everything I build on it is portable to any Postgres host on earth.

That portability is the whole game. I get the managed conveniences — instant REST and realtime, an auth system wired to the database, generous tooling — but the data sits in a standard Postgres instance. The day Supabase no longer fits, I run pg_dump, point my app at a different host, and I'm done. Try that with a proprietary serverless datastore.

For transcribe.so, which moves a lot of audio and transcript data through background jobs, that "it's just Postgres" property let me use real SQL, real indexes, and a real query planner instead of fighting a NoSQL model that pretends joins don't exist. When I needed a job queue, I built it in Postgres rather than adding a broker. One fewer thing to operate.

Auth: integrated beats best-of-breed for a small team

Supabase Auth lives next to my data and drives Row Level Security policies directly. That integration is the point. A standalone identity provider is more powerful in isolation, but it adds a network hop, a second dashboard, a second bill, and a sync problem between "who the user is" and "what rows they can touch."

When auth and authorization are enforced in the same database that holds the data, a whole category of "the token said yes but the query said no" bugs disappears. For a solo operator, fewer moving parts beats marginal feature wins almost every time.

Billing: Stripe, and treat webhooks as truth

Billing is the one place I refuse to be clever. Stripe is the default, and the only hard-won rule I'll insist on is this: your webhook handler is the source of truth, not your checkout success page. Users close tabs. Networks drop. The success redirect is a hint; the checkout.session.completed webhook is the fact.

I learned to respect payment correctness at Klarna, where getting money state wrong isn't a bug, it's an incident. So in my own products, subscription state is reconciled from Stripe webhooks into Postgres, and the app reads its own database — never Stripe's API on the hot path. That keeps billing fast, auditable, and resilient to Stripe being slow.

Why "no vendor lock-in" is a feature, not a principle

People treat lock-in avoidance like an ideology. For me it's pure economics. Lock-in costs you in three concrete ways:

  • Pricing leverage. A vendor you can't leave has no reason to keep your bill reasonable.
  • Velocity. When a managed service can't do the thing you need, you're stuck waiting on their roadmap instead of writing the code yourself.
  • Survival. Services get acquired, deprecated, and repriced. Portable data means none of that is fatal.

Every layer above is chosen so I can swap it without rewriting the product:

  • Postgres → move to any Postgres host.
  • Next.js → deploy to Vercel today, a VPS tomorrow, with no app rewrite.
  • Stripe → the abstraction is thin and the data is in my own tables.

That's the difference between a stack that's convenient and a stack you actually own.

What this stack is not for

I'd be lying if I said this was universal. If you're building a real-time multiplayer game, a high-frequency trading engine, or something that needs a graph database at its core, this isn't your stack. It's optimized for the most common case that actually exists: a web-based SaaS with users, subscriptions, and data, run by a small team that needs to ship and stay alive.

For that case — which is most cases — it's hard to beat.

Frequently Asked Questions

Is Supabase production-ready for a real SaaS?

Yes — it's Postgres underneath, which has run mission-critical systems for decades. Both of my products run on it in production. The managed layer gives you speed early on, and because the data is standard Postgres, you're never trapped if you outgrow the managed offering.

Why not just use a serverless or NoSQL database?

Because most SaaS data is relational, and proprietary datastores make it expensive or impossible to leave. With Postgres you get real SQL, real joins, and a clean migration path to any host. I'd rather pay a small learning cost up front than a lock-in tax forever.

How do I handle background jobs without adding more infrastructure?

Start with a queue inside Postgres before reaching for a dedicated broker. For most workloads it's plenty, it's observable with plain SQL, and it's one fewer service to run. I only graduate to a separate worker fleet when the volume genuinely demands it, which is exactly what I did for the heavier pipeline in transcribe.so.

Does avoiding vendor lock-in mean more work?

Slightly more up front, far less later. You still use managed services for convenience — you just keep your data and core logic portable so switching is a config change, not a rewrite. It's insurance you'll be glad you bought the first time a vendor reprices or shuts down.


If you're weighing this stack for your own product and want a second opinion from someone who runs it in production every day, book a call.

Have something that needs shipping?

I'm Seunghun Lee — I design, build, and ship production AI agents and full-stack SaaS. Tell me what you're building.