What changes when your software stops serving one client and starts serving many — multi-tenancy, RLS, and the decisions you can't undo.
org_id on every table · RLS in the database, not the app · outsource billing · decide early what can't be undone
Building software for one client is different from building a product. In the first case, you solve a specific problem with known business rules and a single set of users. In the second, you have to serve N companies that don't know each other — and can't see each other.
The first time we tried to turn a client feature into a product, we discovered almost none of the code was reusable. Schema, authentication, permissions, billing, onboarding — everything had to be rethought.
What looked like an extension was a brand-new project.
The real difference between a client app and a multi-tenant SaaS isn't on the frontend. It's in how data is isolated, how auth is modeled, and where the line sits between platform code and the company that subscribes to it.
Every SaaS decision starts here: how two companies share the same database without ever seeing each other's data. The wrong call at this point costs you a rewrite by the second customer.
→ When isolation depends on frontend code, a single bug in one query is enough to leak data between customers. With RLS, even a SELECT * with no filter only returns what the logged-in org is allowed to see.
Building SaaS solo or with a small team forces you to reduce decisions. Each piece is there for a concrete reason — almost always because it removes infrastructure code that adds nothing to the product.
→ None of these picks are opinion — they fall out of two rules: (1) don't write what you can outsource, (2) let the database solve what the database can solve.
Some early choices are nearly invisible and become impossible to undo once the product has paying customers. Worth pausing to decide before the first line of code.
does a user belong to 1 org or several? email invites? Changing this later breaks the whole permission schema
charge per seat, per usage or flat plan? Defines plan schema and limits — refactoring is painful
self-service or manual approval? Defines everything: signup, org creation, trial, Stripe activation
if a customer asks to leave with their data, can you deliver? GDPR and LGPD require it — think early or scramble later
how do you ship features to some customers without branching? Decide early or you'll end up with if(orgId === 'X') in the code
None of these decisions need to be perfect at MVP. But all of them need to be conscious — the only one that really hurts is the one made out of ignorance.
Define the problem with one real customer. Who they are, what hurts, how much they'd pay. Without a concrete customer, any SaaS is a hypothesis.
Model the schema with org_id on every table from the very first CREATE TABLE. Write RLS policies before any query lands in the app.
Working MVP: signup → create org → main flow → 1 complete use case. No Stripe yet. The goal is to validate usage, not to charge.
Stripe + plans + limits. Self-service onboarding. Per-org usage logs. From here on it's a product, not a prototype.
Iterate based on what your first 3 customers do (and don't do). Cut features no one uses. Listen for the recurring request.
SaaS isn't tech — it's software distribution with recurring billing. If your product doesn't solve a problem someone would pay every month to solve, no stack will save it. Start with the customer, not with the schema.