Skip to content
HomeWorkProcessAboutBlogContact[email protected]
← Back to blog

Building Multi-Tenant SaaS: Architecture and Considerations

Building Multi-Tenant SaaS: Architecture and Considerations. Technical and business considerations for multi-tenant software platforms. Insights from The Proper Motion Company.

Multi-tenancy is the architectural pattern that makes SaaS economics work. Instead of deploying a separate instance of your application for each customer, you run a single instance that serves all customers simultaneously, with each customer’s data isolated from every other customer’s data. This is what lets a SaaS company serve 500 customers with the same infrastructure team that would otherwise manage one or two deployments.

But multi-tenancy is not a single decision – it is a spectrum of isolation models, each with different tradeoffs in cost, complexity, security, and performance. Getting this wrong creates problems that are extraordinarily expensive to fix later: data leaks between customers, performance interference (“noisy neighbor” problems), and compliance failures that can end enterprise deals before they start.

The Isolation Spectrum: Shared Everything to Shared Nothing

Multi-tenant architecture falls on a spectrum with three major positions.

Shared everything (pool model): All tenants share the same application instances, the same database, and the same tables. Tenant isolation is enforced at the application layer through a tenant_id column on every table and query filtering. This is the cheapest to operate and the simplest to deploy. A single PostgreSQL database can serve hundreds or thousands of tenants if indexed properly. The risk: a single missing WHERE clause in any query leaks data across tenants. This model requires rigorous code review and, ideally, automated testing that verifies tenant isolation on every database query.

Shared infrastructure, isolated data (bridge model): All tenants share the same application instances, but each tenant gets their own database schema or their own database instance. The application routes requests to the correct database based on the tenant identifier. This provides stronger data isolation – a bug in one query cannot accidentally return another tenant’s data because the data simply is not in the same database. The cost is higher: each tenant’s database consumes resources even when idle, and database migrations must be applied to every tenant’s schema individually.

Shared nothing (silo model): Each tenant gets their own complete deployment – application instances, databases, and potentially their own infrastructure. This provides the strongest isolation and the most flexibility (you can run different versions for different tenants), but it is the most expensive to operate and the hardest to maintain. Every deployment, update, and migration must be rolled out to each tenant independently.

The decision framework: start with the pool model unless you have a specific reason not to. Move toward the bridge model when enterprise customers require contractual data isolation guarantees (common in healthcare, finance, and government). Use the silo model only for the largest enterprise customers who require dedicated infrastructure, often for regulatory compliance (data residency, specific cloud region requirements) or performance isolation.

Most successful SaaS platforms use a hybrid: pool model for self-serve and SMB customers, bridge or silo model for enterprise customers who pay enough to justify the operational overhead. Stripe, for example, runs a pool model for most merchants but offers dedicated infrastructure for their largest enterprise clients.

Related: The AI Technology Stack: Models, Frameworks, and Infrastructure Guide

Data Model Design for Multi-Tenancy

The data model is where multi-tenancy succeeds or fails at the operational level. In the pool model, every table that contains tenant-specific data needs a tenant_id column, and every query against those tables must filter by tenant ID. No exceptions.

The most reliable way to enforce this is at the database level using PostgreSQL’s Row Level Security (RLS). RLS policies are defined on each table and automatically filter rows based on the current session’s tenant context. Even if application code forgets to include a tenant filter, the database will not return rows belonging to other tenants. Here is what this looks like in practice:

A policy like CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.current_tenant')::uuid) ensures that any SELECT, UPDATE, or DELETE on the orders table only affects rows where the tenant_id matches the value set in the session variable. The application sets this variable at the beginning of each request, and the database enforces isolation transparently.

RLS adds a small performance overhead (typically 2-5 percent on query execution time) but provides a safety net that is worth far more than the cost. Combine it with application-level filtering for defense in depth.

For the bridge model, use a schema-per-tenant approach within a single database instance. PostgreSQL supports multiple schemas within one database, each with its own set of tables. The application routes to the correct schema using SET search_path = tenant_abc. This keeps tenant data physically separated while allowing shared infrastructure (connection pooling, backups, monitoring) at the database instance level.

Indexing strategy matters more in multi-tenant databases than in single-tenant ones. Every query that filters by tenant_id should have tenant_id as the first column in its composite index. An index on (tenant_id, created_at) is far more useful than separate indexes on tenant_id and created_at because it allows the database to efficiently narrow to a single tenant’s data before sorting by date.

Tenant Onboarding and Configuration

The onboarding experience for a new tenant determines how quickly they see value and how much manual work your team does per signup. A well-built multi-tenant system can provision a new tenant in under 30 seconds with zero human intervention.

Automated provisioning should handle creating the tenant record and generating the tenant identifier, provisioning the data layer (seeding default data, creating the schema if using bridge model), configuring default settings (timezone, currency, notification preferences), setting up the initial admin user and sending the activation email, and provisioning any external resources (a subdomain, a Stripe customer object, a dedicated email sending domain).

Tenant configuration needs to be flexible enough to accommodate different customer needs without creating per-tenant code branches. Common configurable dimensions include branding (logo, primary color, favicon, custom domain), feature flags (which modules are enabled for this tenant, based on their plan), workflow settings (approval chains, notification rules, data retention periods), and integration settings (API keys for third-party services the tenant connects).

Store configuration in a dedicated tenant_settings table with a key-value structure, and cache it aggressively. Tenant configuration is read on virtually every request (to determine feature access, branding, etc.) but changes rarely. A Redis cache with a 5-minute TTL and cache invalidation on writes keeps configuration lookups at sub-millisecond latency.

See also: Privacy-First Software Development as Competitive Advantage

Performance Isolation and the Noisy Neighbor Problem

The “noisy neighbor” problem occurs when one tenant’s heavy usage degrades performance for other tenants. A single tenant running a massive data export, a complex report, or an API integration that generates thousands of requests per minute can saturate shared resources – database connections, CPU, memory, network bandwidth – and affect every other tenant on the platform.

Mitigation strategies, in order of implementation priority:

Rate limiting per tenant: Limit API requests, background job submissions, and bulk operations per tenant. A typical starting point: 100 API requests per minute for the standard plan, 1,000 for enterprise. Implement rate limiting at the API gateway or application middleware layer, using a token bucket algorithm backed by Redis.

Query timeouts: Set a maximum execution time for database queries (30 seconds is a reasonable default). A tenant with a poorly structured custom report should get a timeout error, not lock up the database for all tenants.

Resource quotas: Limit storage per tenant (e.g., 10GB for standard, 100GB for enterprise), concurrent background jobs (e.g., 5 for standard, 50 for enterprise), and maximum file upload sizes.

Connection pooling per tenant: Use PgBouncer or a similar connection pooler with per-tenant connection limits. If your database supports 200 connections, do not allow any single tenant to hold more than 20.

Queue isolation: If background jobs are processed through a queue (Sidekiq, Bull, Celery), assign dedicated queue workers to high-priority tenants or critical job types. A bulk import job for one tenant should not block notification delivery for all tenants.

Monitor per-tenant resource consumption continuously. Build a dashboard that shows the top 10 tenants by database query time, API request volume, storage usage, and background job count. This data tells you which tenants are approaching limits and which might need to be moved to a higher isolation tier.

Billing, Metering, and Plan Management

Multi-tenant SaaS billing is more complex than it appears. You need to track usage, enforce plan limits, handle upgrades and downgrades, manage trial periods, and integrate with a payment processor – all while maintaining accuracy across potentially thousands of tenants.

Usage metering should be event-driven. When a tenant performs a billable action (API call, document processed, user added, storage consumed), emit an event to a metering service. The metering service aggregates these events and produces usage summaries for billing. Do not compute usage from your primary database at billing time – the aggregation queries will be slow and will hit your production database during billing runs.

Plan limits should be enforced in real-time, not after the fact. When a tenant on the “Starter” plan tries to add their 11th user (limit: 10), the system should reject the request immediately with a clear message pointing them to the upgrade path. Enforcing limits retroactively – “you used 150 percent of your allocation, here is an overage charge” – creates billing disputes and erodes trust.

The plan model should be stored as configuration, not code. Define each plan as a set of feature flags and numeric limits: { "max_users": 10, "max_storage_gb": 5, "api_rate_limit": 100, "features": ["basic_reporting", "email_support"] }. When you introduce a new plan or adjust limits, you change configuration, not code. This lets your sales and product teams iterate on pricing without engineering involvement.

Compliance and Enterprise Requirements

Enterprise customers drive multi-tenant SaaS revenue disproportionately – a single enterprise contract can equal hundreds of self-serve accounts. But enterprise procurement comes with requirements that your architecture must support.

SOC 2 compliance requires demonstrating that tenant data is isolated, access is controlled, and audit trails exist. This means comprehensive logging (who accessed what data when), encryption at rest and in transit, access control reviews, and incident response procedures. SOC 2 is table stakes for selling to mid-market and enterprise customers in the US.

Data residency requirements mandate that a tenant’s data be stored in a specific geographic region. European customers may require EU data residency under GDPR. Government customers may require domestic data residency. Your architecture needs to support region-specific database deployments, either through the silo model for these tenants or through a bridge model with region-specific database instances.

Single Sign-On (SSO) via SAML 2.0 or OIDC is expected by every enterprise customer. Implement SSO as a tenant-level configuration: each tenant can optionally configure their identity provider, and when enabled, their users authenticate through the tenant’s IdP rather than your built-in authentication system. Support the major IdPs (Okta, Azure AD, Google Workspace, OneLogin) and test with each one, because SAML implementations vary subtly between providers.

Data export and portability: Enterprise customers want assurance that they can leave. Provide a comprehensive data export that includes all of the tenant’s data in a standard format (CSV, JSON, or both). This is not just a feature – it is a trust signal that you are confident enough in your product’s value that you do not need to rely on data lock-in.


Multi-tenant architecture is one of the highest-leverage decisions in building a SaaS platform. Done well, it gives you the economics to serve thousands of customers efficiently while meeting the security and compliance requirements of your most demanding accounts. Done poorly, it creates scaling walls, security vulnerabilities, and operational nightmares that compound as your customer base grows.

If you are building a multi-tenant SaaS platform and want to get the architecture right from the foundation, talk to our team. We have designed and built multi-tenant systems across industries and can help you choose the right isolation model for your specific requirements.

// Related posts