Skip to content
Starone

Reference Architecture

Illustrative

Multi-Tenant SaaS Platform

A SaaS architecture that separates the control plane from the application plane and carries tenant identity through every layer, from the edge to the data store.

The problem

Consider a software product sold to many organisations, from small teams on a self-service plan to large enterprises with security questionnaires and procurement processes. All of them expect their data to be invisible to every other customer, and the larger ones expect single sign-on, audit logs and predictable performance.

Serving every customer from a separate deployment is simple to reason about and expensive to run and upgrade. Serving them all from one shared deployment is efficient and makes isolation, fair resource use and per-customer configuration into engineering problems. The architecture has to choose where on that spectrum each tier of customer sits.

Requirements the design must meet

  • One tenant must never be able to read or modify another tenant's data, and this must be enforced below the application code.
  • A new tenant must be provisioned automatically, without an engineer performing manual steps.
  • Enterprise tenants must be able to use their own identity provider and manage users through automated provisioning.
  • Heavy usage by one tenant must not degrade the experience of others.
  • Features, limits and billing must follow from a tenant's plan and be changeable without a deployment.
  • Usage, errors and performance must be attributable to an individual tenant.

The design

Components

Multi-tenant SaaS architecture
  1. Tenant-aware Edge

    • Custom domains
    • Tenant resolution
    • WAF
    • Per-tenant rate limits
  2. Identity & SSO

    • SAML and OIDC
    • SCIM provisioning
    • Roles and permissions
    • MFA
  3. Control Plane

    Manages tenants, never serves their traffic

    • Tenant lifecycle
    • Plans and entitlements
    • Billing and metering
    • Feature flags
  4. Application Plane

    • Stateless services
    • Background jobs
    • Tenant context
    • Webhooks
  5. Data Isolation

    Isolation model chosen per plan tier

    • Row-level security
    • Schema per tenant
    • Dedicated databases
    • Per-tenant keys
  6. Per-tenant Observability

    • Usage metrics
    • Tenant-tagged traces
    • Noisy-neighbour alerts
    • Audit logs
A control plane manages tenants, plans and billing, while the application plane serves them. Tenant identity is resolved at the edge and carried through every layer down to the data store and the telemetry.
01

Tenant-aware edge

The edge resolves which tenant a request belongs to from its subdomain, custom domain or token, and rejects requests it cannot attribute. It applies rate limits per tenant so that one customer's traffic spike is contained. Custom domains and their certificates are issued and renewed automatically.

02

Identity and single sign-on

The identity layer supports password and MFA sign-in for smaller customers, and SAML or OIDC federation with SCIM provisioning for enterprises. Roles and permissions are defined per tenant. Every issued token carries the tenant identifier as a signed claim, which downstream services trust in place of any client-supplied value.

03

Control plane

The control plane owns the tenant lifecycle: sign-up, provisioning, plan changes, suspension and deletion. It holds the catalogue of plans and entitlements, and is the source of truth for what each tenant is allowed to use. It is deployed and scaled separately from the application plane, so that an incident in one does not take down the other.

04

Application plane

Stateless services handle product traffic and establish tenant context once, at the start of each request, from the verified token. That context is propagated to database sessions, background jobs, caches and outgoing events. Work queues are partitioned so that one tenant's backlog cannot starve another's jobs.

05

Data isolation

Standard tenants share a PostgreSQL database in which row-level security policies restrict every query to the current tenant. Tenants with stricter requirements can be placed in a dedicated schema or a dedicated database, selected by a routing layer. Cache keys, object storage paths and search indexes are all prefixed or partitioned by tenant.

06

Metering and billing

Services emit usage events, which are aggregated per tenant into the quantities that plans are priced on. The billing integration turns those into invoices through a payment provider, and entitlement checks read the same data to enforce limits. Usage events are idempotent, so retries do not result in double charging.

07

Per-tenant observability

Every log line, metric and trace is tagged with the tenant identifier. This allows support to see one customer's experience, and allows engineers to detect a noisy neighbour before others notice. An audit log of security-relevant actions is available to each tenant's administrators.

Trade-offs

Design decisions

DecisionWhy
A shared database with row-level security as the defaultA database per tenant gives the strongest isolation and multiplies cost, migration time and operational work with every customer. Pooling with row-level security keeps the fleet small and upgrades simple, and relies on policies enforced by the database so that a missing filter in application code does not become a data leak.
Dedicated schemas or databases offered as a tier, not as the baselineSome customers need isolation that pooling cannot provide, for contractual or residency reasons. Supporting more than one isolation model adds a routing layer and complicates migrations, so it is reserved for the tenants whose requirements justify it.
A control plane separate from the application planeFolding tenant management into the product services is quicker to build at first. Separating it means two systems to deploy, and gives a clear place for provisioning, entitlements and billing that can change on its own schedule and fail without affecting customer traffic.
Tenant context derived from the signed token onlyAccepting a tenant identifier from a header or request body is convenient and is a common source of cross-tenant access bugs. Taking it only from a verified claim removes that class of error, at the cost of making some internal tooling and support workflows more deliberate.
Entitlements evaluated at runtime instead of per-plan deploymentsShipping different builds per plan fragments testing and slows releases. A single codebase with runtime entitlement checks adds a lookup on the request path, which is cached, and allows plans and limits to change without a release.

Intended outcomes

  • Tenant isolation that is enforced by the platform, not by developer discipline
  • Onboarding that is automated from sign-up to a working tenant
  • Enterprise identity requirements that are met without custom work per customer
  • Usage and performance that can be understood one tenant at a time

What the design is built to achieve. Illustrative, not measured results from a client project.

Representative technologies

  • TypeScript
  • Next.js
  • Node.js
  • Spring Boot
  • PostgreSQL
  • Redis
  • Kafka
  • Kubernetes
  • Terraform
  • OIDC / SAML / SCIM
  • OpenTelemetry
All reference architectures

Have a system that needs to work in production?

Tell us what you are building. An engineer will read it and reply within two working days.