Product companies

SaaS platform engineering

A pattern for building and running multi-tenant SaaS as a platform rather than a growing application. It covers tenancy and isolation, entitlements, billing, tenant-aware data access, background work and the delivery pipeline that lets a small team ship safely and often.

Row-level tenant isolation with enforced query scoping Entitlement and feature-flag service Usage metering with idempotent billing events Subscription and payment provider integration
The situation

When this pattern is the right one.

Multi-tenancy is usually treated as a schema decision and then becomes a source of incidents across the whole codebase. Product teams also accumulate bespoke variants per customer, so the platform becomes a growing set of conditionals that nobody can reason about.

01

Tenant identity is spread across the codebase instead of being enforced at one boundary

02

Background jobs and caches have no reliable notion of which tenant they belong to

03

Plan limits and entitlements are checked in the interface but not in the domain logic

04

Every customer-specific request produces another branch and another regression risk

05

Releases are infrequent because the pipeline is slow, which makes each release larger and riskier

The approach

How the work is done.

We make tenancy a property of the request and of the data access layer, so a query cannot accidentally cross a customer boundary. Entitlements become a first-class domain concept evaluated server-side, which means the interface can never grant a capability the plan does not include. Feature differences are modelled as configuration and extension points rather than branching. Everything else follows from delivery discipline: fast pipeline, reversible releases, and per-tenant observability so a single customer problem can be diagnosed without affecting the rest.

Tenant context resolved once per request and enforced at the data-access boundary

Entitlements and plan limits evaluated in domain logic, never only in the interface

Configurable feature flags replacing per-customer code branches

Usage metering and billing events recorded immutably and reconciled against provider data

Tenant-scoped queues, caches, rate limits and observability dimensions

Trunk-based delivery with feature flags and automated rollback triggers

Indicative stack

What this is usually built with.

Chosen per problem rather than run as one stack for everything. The list below is representative, not a commitment.

Representative componentsselected per constraint
Row-level tenant isolation with enforced query scoping
Entitlement and feature-flag service
Usage metering with idempotent billing events
Subscription and payment provider integration
Tenant-aware queues, caching and rate limiting
Infrastructure as code with per-environment pipelines
Per-tenant metrics, logs and tracing
Contract testing for public and partner APIs
What it supports

The outcome this pattern is chosen for.

This pattern is designed to support a product that can be sold to organisations of different sizes and shapes without the codebase fragmenting. It is built to keep the cost of adding a tenant low and the risk of leaking one low.

01

Keeps the cost of onboarding a new customer shape low and predictable

02

Makes isolation a property of the platform rather than a discipline every developer must maintain

03

Lets plan and pricing changes ship as configuration rather than as a release

04

Shortens the path from commit to production while keeping each release reversible

05

Makes a single tenant’s failure diagnosable without impacting the others

Watchouts

The parts that tend to go wrong.

Written down because they are the same parts that go wrong everywhere, and knowing them up front is cheaper than discovering them halfway through.

Retrofitting tenant scoping after launch means auditing every query, and the gaps are found in production

Schema-per-tenant approaches make migrations, backups and connection management dramatically harder

A metered usage pipeline that is not idempotent produces billing disputes that are expensive to unwind

Feature flags accumulate; without ownership and expiry dates they become a second, undocumented codebase

Premature multi-region design adds cost and complexity long before it is required

Note

These are solution patterns, not client case studies. Each one describes a reusable engineering approach and the problem shape it addresses. No client is named and no result is claimed.

Note

Nothing here reports a measured outcome. The outcome sections describe what each pattern is designed to support, and what a team should expect to be able to do once it is in place.

Note

Named references, implementation detail and engagement history can be discussed directly on request, subject to client confidentiality.

Note

This page is structured so that verified case studies can be added alongside these patterns without changing the underlying format.

Recognise your situation in this one?

Patterns are general. The engineering decisions are not, and they are worth discussing against your actual constraints.

Start a conversation All patterns