A SaaS MVP is the smallest version of a subscription product that a real customer can sign up for, use for its main job, and pay for. It is harder to scope than a one-off app, because the parts nobody sees (accounts, teams, roles, billing, tenant isolation) have to work from day one. This guide covers the SaaS product development process we follow: how to scope the MVP, how to choose a tenancy model, how to set up billing, the tech stack we start from, and a launch checklist. It includes a short Node.js example for tenant isolation.
What a SaaS MVP has to include
A normal MVP tests one question: do people want this? A SaaS MVP tests a second one too: will a company pay for it every month? That second question brings requirements a prototype can skip.
- Accounts that belong to an organization. Business buyers sign up as a company, invite colleagues and expect roles.
- Tenant isolation. One customer must never see another customer's data. This is a design decision, and it is expensive to retrofit.
- Billing. Plans, trials, upgrades, failed payments and cancellations. Each of these changes what the user can do in the product.
- An admin view for you. You need to see who signed up, what plan they are on and where they got stuck.
- The one core job. The feature that the customer is paying for, done well.
Everything else can wait. The table below is the split we use in scoping.
| Build in the MVP | Leave for later |
|---|---|
| Sign-up, login, password reset, email verification | Single sign-on (unless your first buyers require it) |
| Organizations, invitations, two or three roles | Custom roles and fine-grained permissions |
| One core workflow, end to end | Second and third workflows |
| One or two plans, a trial, card payments | Coupons, annual invoicing, reseller pricing |
| Tenant isolation and audit of key actions | Per-tenant customization and white-labelling |
| Basic internal admin and product analytics | Customer-facing reporting dashboards |
Scope it: one job, one buyer, one paid plan
Most SaaS MVPs that run long started with a feature list. Start with a sentence.
- Name the buyer. "Operations managers at 20 to 200 person logistics firms" is a buyer. "Businesses" is not.
- Name the job. Write what the buyer does today without your product, and the one step you replace.
- Define the paid moment. Decide what a customer gets on the paid plan that they don't get in the trial. If you can't say it, the plan isn't ready.
- Write the first-session path. List every screen from sign-up to the first useful result. Anything not on that path is a candidate to cut.
- Set the launch test. For example: five companies complete the core job twice in two weeks, and three of them add a card.
- Write down what's out. Keep the list. It becomes your roadmap after launch.
If the core job depends on a language model, scope the AI part separately and test it first. Our guide to building an AI MVP covers that.
Choose a tenancy model before you write code
Multi-tenancy means many customers share one running product. The AWS SaaS Lens describes three models, and the names are widely used.
| Model | How it works | Good for | Watch out for |
|---|---|---|---|
| Pool | All tenants share one database and one set of tables; every row carries a tenant ID | Most MVPs: cheapest to run, simplest to deploy | Every query must be scoped to the tenant; one missed filter is a data leak |
| Bridge | Shared application, separate schema or database per tenant | Customers who ask for stronger separation | Migrations run once per tenant; more moving parts |
| Silo | A separate stack per tenant | Regulated or very large customers | Highest cost and operational work |
We start most MVPs on the pool model and make isolation a property of the database, not of each query. PostgreSQL's row-level security does this: you enable it per table and write a policy, and the database refuses rows from other tenants even when application code forgets a filter.
```sql
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
ALTER TABLE projects FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON projects
USING (tenant_id = current_setting('app.tenant_id')::uuid);
```
The application then sets the tenant for each request inside a transaction. Here is a small helper with node-postgres:
```js
import pg from "pg";
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
// Runs work in a transaction where every query is limited to one tenant.
export async function withTenant(tenantId, work) {
const client = await pool.connect();
try {
await client.query("BEGIN");
// The third argument (true) makes the setting last for this transaction only.
await client.query("SELECT set_config('app.tenant_id', $1, true)", [tenantId]);
const result = await work(client);
await client.query("COMMIT");
return result;
} catch (err) {
await client.query("ROLLBACK");
throw err;
} finally {
client.release();
}
}
// Usage: the query has no tenant filter, and still returns only this tenant's rows.
const projects = await withTenant(session.tenantId, (db) =>
db.query("SELECT id, name FROM projects ORDER BY created_at DESC")
);
```
Two details matter. PostgreSQL's documentation notes that table owners bypass row security unless you use FORCE ROW LEVEL SECURITY, and superusers always bypass it, so the application should connect with a role that is neither. And the tenant ID must come from the verified session on the server, never from a value the browser sends.
Broken access control is the first item in the OWASP Top 10 (2021). In a SaaS product, a cross-tenant leak is the most damaging form of it, which is why we treat isolation as part of the MVP and write automated tests that log in as tenant A and try to read tenant B's records.
Billing: let the payment provider be the source of truth
Billing is where SaaS MVPs most often lose time. The pattern that holds up is simple: the payment provider owns subscription state, and your product keeps a copy that it updates from webhooks.
- Use hosted pages. Stripe Checkout takes the payment, and the customer portal lets customers update cards, change plans and cancel. You don't build those screens.
- Sync through webhooks. Stripe's subscription guide lists the events to handle, including
checkout.session.completed,customer.subscription.updated,customer.subscription.deleted,invoice.paidandinvoice.payment_failed. - Verify and de-duplicate. Verify the signature on every webhook, and store processed event IDs, because providers can deliver the same event more than once.
- Gate features from one place. Keep a single function that answers "what can this organization do?" from the stored plan and status. Don't scatter plan checks through the code.
- Decide the failed-payment path. Choose what happens when a card fails: how long access continues, and what the user sees.
Attach the subscription to the organization, not to the person who entered the card. People leave companies; the account should not leave with them.
The SaaS tech stack we start from
A boring default lets the budget go into the core job. This is our starting point for a web-based SaaS MVP in JavaScript and TypeScript.
| Layer | Default | Change it when |
|---|---|---|
| App and API | Next.js (App Router) with TypeScript | You need a separate API for mobile apps or partners from day one |
| Database | PostgreSQL with row-level security | The data is not relational, which is rare for business software |
| Auth and organizations | A managed auth provider with organizations and invitations | Buyers require SSO or on-premise identity from the start |
| Billing | Stripe Checkout, customer portal and webhooks | You only sell annual contracts by invoice |
| Background jobs | A managed queue or scheduled functions | Jobs are long-running or need strict ordering |
| A transactional email service with your own domain | You need in-house delivery for compliance reasons | |
| Hosting | A managed platform with preview deployments | You have data-residency rules that need a specific cloud region |
| Monitoring | Error tracking, structured logs, uptime checks | Volume justifies a full observability platform |
A mobile app is usually a later step. If the buyer works at a desk, ship the web product first and add mobile apps once the core job is proven.
The development process, phase by phase
We don't publish week counts, because the same phase varies widely between products. What matters is what each phase must produce before the next one starts.
| Phase | Goal | Done when |
|---|---|---|
| Discovery | Buyer, job, paid moment, risks | A one-page scope and the first-session path are agreed |
| Foundations | Auth, organizations, roles, tenancy, deployment | Two test tenants exist and cannot read each other's data |
| Core workflow | The one job, end to end | A real user finishes it without help |
| Billing | Plans, trial, checkout, webhooks, feature gates | A test customer can subscribe, upgrade, fail a payment and cancel |
| Hardening | Security review, backups, monitoring, onboarding emails | The launch checklist below passes |
| Private launch | First real customers | The launch test from your scope is measured |
What makes it longer: integrations with other systems, data imports from a customer's old tool, more than two or three roles, and compliance requirements such as SSO or data residency. What makes it shorter: one buyer, one workflow, and a decision-maker who answers questions quickly.
Launch checklist
- Tenant isolation is enforced in the database, and automated tests try to cross tenants.
- Roles are checked on the server for every action, not only hidden in the interface.
- Passwords are handled by the auth provider; sessions expire and can be revoked.
- Webhook signatures are verified and events are processed once.
- A failed payment, a cancellation and a plan change have each been tested end to end.
- Backups run automatically, and a restore has been tested once.
- Errors and slow requests reach a person, with the tenant and user attached.
- Sign-up, invitation, password reset and receipt emails are delivered from your own domain.
- A privacy policy, terms and a data processing agreement exist, and you know where customer data is stored.
- You can export or delete one customer's data on request.
- There is a staging environment, and deployments can be rolled back.
- Product analytics record the first-session path, so you can see where new users stop.
Common mistakes
- Building for the second customer first. Custom roles, white-labelling and reporting get built before one customer has paid.
- Adding tenancy later. A product built for one customer and then "made multi-tenant" needs every table and query revisited.
- Writing your own billing logic. Proration, taxes and retries are solved problems. Use the provider's.
- No admin view. The team ends up running SQL by hand to answer support questions.
- Choosing the stack for scale you don't have. Microservices and multiple databases slow an MVP down and rarely help it.
What we've built
Two products we've shipped show the pattern. TMS is our own multi-tenant team management SaaS MVP, with Kanban boards, sprints, check-ins, HR and payroll. Cheggl is a German video business directory with a company dashboard, an admin console and AI search. Both started from a narrow core job and grew from there.
Want help building your SaaS MVP?
We scope and build SaaS MVPs in TypeScript, with tenancy and billing in place from the first release. Tell us the buyer and the job on our SaaS development page, or read how we approach MVP development. If you already have a product and want to add AI features, see our guide to integrating AI into a SaaS product.
Sources
- AWS Well-Architected SaaS Lens
- AWS SaaS Lens: Silo, pool and bridge models
- PostgreSQL: Row security policies
- node-postgres: Transactions
- Stripe: How subscriptions work
- Stripe: Using webhooks with subscriptions
- Stripe: Receive events in your webhook endpoint
- OWASP Top 10 (2021): Broken Access Control
- Next.js: App Router documentation



