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 callHow 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.
- 1Step 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.
- 2Step 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.
- 3Step 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.
- 4Step 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.
- 5Step 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.
- 6Step 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
| Model | Choose it when | What it costs you |
|---|---|---|
| Shared schema, tenant column | Self-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 tenant | Customers 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 tenant | Regulated 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 callSubscription 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:
- 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.
- 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.
- 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.
- Read replicas for reporting. Analytical queries and transactional traffic compete badly; separating them protects the interactive experience.
- Per-tenant rate limits. One customer's bulk import should not degrade everyone else's product. In multi-tenant systems, fairness is a feature.
- 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
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 →