SaaS development: multi-tenant platforms built to survive their own growth

We build multi-tenant SaaS platforms that scale from first customer to first million ARR. The work that decides whether that happens smoothly is done early and is mostly invisible: the tenancy model, how isolation is enforced, and whether billing is connected to entitlements or scattered through the codebase.

What makes SaaS different from building a web application

A web application serves users. A SaaS product serves organisations that pay on a recurring basis, which introduces four concerns a standard application build does not have: many customers' data sharing one system without ever meeting, subscriptions that change mid-cycle, permissions that customers administer themselves, and a cost base that has to stay below revenue per account as usage grows.

Each of those is far cheaper to design in than to retrofit. That is the whole argument for spending the first week on architecture rather than on features.

Planning a SaaS build and want the architecture pressure-tested?

Book a free 30-minute discovery call

How we build a SaaS platform

The order matters here. Steps one to four are difficult to change later; step six is deliberately deferred until there is evidence to guide it.

  1. 1
    Step 1

    Decide the tenancy model before writing schema

    Shared schema with a tenant column, schema-per-tenant, or database-per-tenant. This is the one decision that is genuinely painful to reverse, because it propagates into every query, migration and backup procedure you will ever write. We pick it against your real constraints — expected customer count, whether any customer will demand data isolation contractually, and how much per-tenant customisation the product must support.

  2. 2
    Step 2

    Tenant isolation enforced below the application

    Filtering by tenant in application code works until one query forgets, and that single omission is a cross-tenant data leak. We enforce isolation at the data layer — row-level security or a scoped query layer that cannot be bypassed by accident — and add tests that specifically attempt to read another tenant's records. Those tests exist to fail loudly during development rather than quietly in production.

  3. 3
    Step 3

    Identity, roles and permissions

    Your customers will ask for team accounts, invitations, role hierarchies and eventually SSO. Retrofitting an organisation layer onto a product built around individual users is a substantial rewrite, so we model organisations, memberships and roles from the start even when the first release only exposes a single role.

  4. 4
    Step 4

    Billing wired to entitlements, not bolted on

    Subscription logic is where SaaS products accumulate the most avoidable damage. Plan changes, proration, trials, failed payments, dunning, seat counts and usage limits all interact. We integrate a billing provider such as Stripe and connect it to an entitlements layer the application checks — so what a customer may do follows from what they pay for, in one place rather than scattered through conditionals.

  5. 5
    Step 5

    Ship the narrow product, instrumented

    We build the smallest coherent product that a customer can pay for, with analytics on activation and usage from day one. Onboarding gets disproportionate attention because activation, not signup, is the metric that determines whether the rest of the roadmap matters.

  6. 6
    Step 6

    Then scale, in the order the data justifies

    Read replicas, caching, background job queues, per-tenant rate limits and index tuning applied when measurement shows they are needed. Scaling work performed before there is load is a way of spending budget on a problem you may never have, and it usually complicates the codebase in the meantime.

Choosing a tenancy model

ModelChoose it whenWhat it costs you
Shared schema, tenant columnSelf-serve or standard B2B product with many customers. Simplest operations, single migration path, lowest infrastructure cost.Isolation depends on discipline — every query must be scoped, so enforcement has to live below the application layer.
Schema per tenantCustomers expect visible separation, or need per-tenant structural customisation.Migrations run per schema and slow down as customers accumulate. Tooling must handle hundreds of schemas.
Database per tenantRegulated or enterprise customers with data residency or contractual isolation requirements; a small number of large accounts.Highest operational burden — provisioning, backups, monitoring and upgrades multiply per customer.

A practical middle path exists and is often correct: build on a shared schema, but keep the data access layer abstracted enough that a demanding enterprise customer can later be moved to an isolated database without rewriting the product. We design for that possibility rather than committing to the expensive model on the chance you will one day need it.

Want a second opinion on your tenancy and billing design?

Book a free 30-minute discovery call

Subscription billing, in more detail

Billing is the subsystem most likely to be underestimated, because the happy path is trivial and everything else is not. These are the cases we build for explicitly:

Mid-cycle plan changes

Upgrades, downgrades and proration. Downgrades are the awkward direction: what happens to data and seats that exceed the new plan's limits has to be a deliberate product decision, not an accident.

Trials and conversion

Trial start and expiry, whether a card is required upfront, and what the product does at expiry — restrict, read-only, or lock. Each choice changes conversion and each needs building.

Failed payments and dunning

Retry schedules, notification sequences and grace periods before suspension. Handled poorly, this silently churns customers who intended to stay.

Seats and usage limits

Counting seats correctly as members are invited and removed, and metering usage where pricing depends on it. Both need to agree with what the billing provider believes.

Entitlements as one source of truth

A single layer the application asks what a tenant may do. Without it, plan logic spreads into dozens of conditionals and changing packaging becomes a code-wide edit.

Webhook reliability

Billing events arrive asynchronously, out of order, and sometimes twice. Handlers must be idempotent, or subscription state drifts away from the provider's.

Scaling considerations

We sequence this work against measurement rather than anticipation, in roughly the order problems actually appear:

  1. Query and index discipline. Almost every early performance complaint is a missing index or an N+1 pattern that was harmless at a thousand rows and is not at a million.
  2. Move slow work off the request. Reports, imports, exports and email belong in a background queue with retries and visibility, not in a web request holding a connection open.
  3. Cache what is read repeatedly. Tenant configuration and permission lookups are read constantly and change rarely — ideal cache candidates, provided invalidation is designed rather than hoped for.
  4. Read replicas for reporting. Analytical queries and transactional traffic compete badly; separating them protects the interactive experience.
  5. Per-tenant rate limits. One customer's bulk import should not degrade everyone else's product. In multi-tenant systems, fairness is a feature.
  6. Watch cost per tenant. Infrastructure spend per account is the number that decides whether growth improves your margin or erodes it, so it should be visible from early on.

Core Technology Stack

Next.jsNode.jsPostgreSQLStripeAWSRedisDockerTypeScript

Related work from our team

Live products built by this team, each involving the subsystems above — accounts, payments, scheduling and multi-role access.

Entrance Dose

A live-class platform with separate student and teacher portals, course management, payment integration and progress tracking, published on the App Store and Google Play.

Flutter · PHP · MySQL · Firebase · Socket.io

See the work →

Gymtaar

A platform pairing users with trainers: booking, in-app video consultation, supplement commerce and tracking. Multiple user roles against shared data. Ongoing engagement.

Flutter · PHP · MySQL · FonePay · Agora

See the work →

Above The Tide Motel

A booking front end integrated with a property management system for reservation and availability handling.

Web · PMS integration

See the work →

Frequently Asked Questions

For most B2B SaaS products, a shared schema with a tenant identifier on every row is the right starting point: it is the simplest to operate, cheapest to run, and scales to a large number of customers. Choose schema-per-tenant when customers require demonstrable data separation or per-tenant customisation, accepting that migrations then run per tenant. Choose database-per-tenant when you are selling to regulated enterprises with data residency obligations or a small number of very large accounts. The mistake we see most often is picking database-per-tenant early for a self-serve product, which multiplies operational work before there is any revenue to justify it.

A focused, payable first version is typically a matter of a few months rather than a few weeks, because a SaaS product needs authentication, an organisation and role model, billing, and an admin surface before anyone can subscribe — none of which are optional. A broader platform with integrations, granular permissions and reporting takes longer. We give a firm timeline after a scoping conversation, because a range quoted before anyone has seen your requirements is not information you can plan around.

Use an established billing provider. Subscription billing looks straightforward and is not: proration on mid-cycle plan changes, trial conversion, failed payment retries, dunning sequences, tax handling across jurisdictions and invoice history are each a source of subtle bugs, and getting them wrong affects revenue directly. We integrate the provider and keep an entitlements layer in your application so pricing and packaging can change without touching feature-gating logic throughout the codebase.

In our experience, the database — and usually through missing indexes and N+1 query patterns that were invisible at low row counts. After that, anything synchronous that should have been a background job, such as report generation, bulk imports or outbound email, because those hold requests open and exhaust connections. Both are cheap to fix when the tenancy model is sound and expensive when it is not, which is why the schema decision comes first.

Yes, and it is a common engagement. We begin with a review covering the tenancy and isolation model, test coverage, dependency currency, deployment process and the highest-risk areas of the code, then give you a written assessment with prioritised work. If we think the honest answer is that a subsystem should be rewritten rather than patched, we will say so and explain the trade-off rather than quietly billing maintenance against a design that cannot hold.

Yes, entirely. Code lives in your repositories and infrastructure runs in your cloud accounts from the beginning of the engagement, with IP assignment agreed in writing before work starts. You are never in a position where leaving us means losing access to your own product or having to migrate off our accounts.

Related services

Let's design your SaaS architecture before it becomes expensive

Book a free 30-minute discovery call