SaaS Architecture
Designing Multi-Tenant SaaS Applications in .NET
Multi-tenancy is an isolation model, not a tenant ID column. Identity, data access, caches, queues, keys, diagnostics and operations must all preserve the same tenant boundary.

Tenant context must come from a trusted boundary
A route such as /tenants/42/orders identifies requested scope; it does not prove the caller belongs to tenant 42. Resolve identity, membership and active tenant through trusted server-side data, then carry a validated context through the operation.
Users can belong to several tenants, services may operate for one tenant and support staff may cross boundaries under controlled authority. Model these cases rather than treating one TenantId claim as permanent truth. Membership can be revoked while a token remains valid.
Authentication establishes who or what is calling. Authorisation decides whether that identity may perform this action on this tenant's resource. Collapsing those questions is the origin of many cross-tenant leaks.
Isolation is a spectrum across several dimensions
Shared application and database infrastructure offers density and simpler fleet management. Dedicated databases or entire deployment stamps increase security, performance and recovery isolation at greater cost and operational complexity. Hybrid models are normal.
Choose separately for compute, data, storage, messaging, keys and telemetry. A tenant can share compute while owning a database, or share a database while using a separate encryption key. “Single tenant” and “multi-tenant” are not complete architecture descriptions.
Base isolation on regulatory obligations, noisy-neighbour risk, recovery granularity, regional placement and price. Dedicated infrastructure is not automatically secure; it still needs correct routing and automation. Shared infrastructure is not automatically unsafe; it needs stronger logical controls.

Database strategy determines more than query syntax
A shared schema with tenant columns maximises density but makes filtering and tenant-aware uniqueness universal concerns. A database per tenant improves isolation and restoration but creates provisioning, connection, migration and monitoring fleets.
Schema per tenant sits between them but can become operationally awkward as tenant count grows. Sharded databases group tenants and introduce a control plane that knows placement. Moving a tenant then becomes a data migration with routing coordination.
Select from expected tenant count, data volume variance, customer requirements and operating capability. Do not choose database-per-tenant for ten thousand small customers without automated lifecycle management, or one shared database for a few enormous customers whose workloads can dominate it.
Global query filters are a guardrail, not the boundary
EF Core query filters can automatically apply tenant predicates and reduce accidental omissions. They can also be bypassed, disabled for administration or defeated by raw SQL. Required tenant scope should be hard to avoid in repositories or data contexts and reinforced by database controls where practical.
Include tenant keys in unique constraints. A global unique username or reference may accidentally prevent different tenants using the same value; omitting tenant scope from a natural key may do the opposite and allow duplicates inside one tenant.
Test for absence, not only presence: can tenant A retrieve, update, delete or infer tenant B's record by identifier? Include bulk operations, joins, projections, imports and administrative endpoints. Cross-tenant security tests deserve a permanent regression suite.
Background work frequently loses tenant context
An HTTP request has an authenticated principal; a queued job may run hours later with only a payload. Put the tenant ID and stable initiating context in the message, validate it at consumption and establish a scoped execution context before accessing data.
Do not serialise an entire access token into a queue. Tokens expire and expose unnecessary credentials. Record who requested the operation for audit, then authorise the worker through its service identity and domain policy.
Recurring jobs need explicit tenant enumeration and fairness. One large tenant must not monopolise workers. Partition queues or apply per-tenant concurrency and quotas where workload variance matters.
Caches are an easy cross-tenant leak
A key such as customer:123 is unsafe if identifiers repeat across tenants. Include tenant and all security-relevant variation in the key. The same applies to output caches, distributed locks, idempotency records and compiled report results.
Tenant scope alone may be insufficient when results depend on user permissions, locale or feature configuration. Cache only data with a clear correctness and invalidation policy. Short expiry reduces persistence, not the severity of a leak.
Avoid placing mutable tenant context in singleton services or static state. ASP.NET Core serves concurrent requests; one incorrectly stored tenant can contaminate another request nondeterministically and become almost impossible to reproduce.
Object storage and search need first-class isolation
Blob path prefixes are organisational conventions unless access is enforced. Generate tenant-scoped object names server-side, authorise before issuing download access and keep signed URLs short-lived and narrow. Do not trust a submitted blob path.
Separate containers or accounts improve isolation and per-tenant lifecycle at growing provisioning cost. Search indexes can be shared with mandatory filters or dedicated. Confirm filters are applied before ranking and faceting; result counts and suggestions can leak information even when documents are hidden.
Exports create new copies outside primary controls. Authorise the request and later download, record ownership, expire files and ensure background generators cannot write one tenant's report into another's location.
Noisy neighbours are a product and architecture problem
Rate-limit expensive operations by tenant as well as globally. Bound concurrent background work, database query cost, storage use and external API spend. Global autoscaling may keep the platform alive while one customer's workload makes the service uneconomic.
Fairness policies need to match pricing and service promises. A fixed quota treats a small and enterprise customer equally; weighted quotas can reflect plans but are more complex. Provide observable limits and recovery rather than surprising users with generic errors.
Deployment stamps can contain blast radius and natural scale limits by assigning groups of tenants to independent copies of the platform. They also require a control plane for placement, provisioning, rollout and fleet visibility.
Tenant-specific configuration can fragment the product
Branding, locales, document templates and feature entitlements are common legitimate variation. Per-tenant code branches and bespoke database columns make upgrades progressively unsafe. Prefer versioned configuration with validation and clear defaults.
Feature flags are useful for progressive rollout and commercial entitlement but those are different purposes. A rollout flag should expire; an entitlement may be permanent. Mixing them makes deletion and access decisions unclear.
Configuration changes are privileged business events. Audit who changed authentication, retention, integrations and permissions. Validate changes before activation so one tenant's invalid configuration cannot break shared workers.
Keys and secrets need deliberate scope
One platform-managed encryption key is operationally simple but gives all tenants the same cryptographic failure domain. Per-tenant keys support stronger isolation and customer-managed requirements while multiplying rotation, availability and recovery work.
Envelope encryption can keep data keys close to tenant data while protecting them with managed keys. The design must preserve key version and recovery; deleting a key is effective data destruction and can be accidental.
Third-party integration credentials belong to the tenant and connector scope. Store them in an appropriate secret store, restrict support visibility and prevent values entering logs or export. Rotation should not require database editing.
Support access is part of the threat model
A global “super admin” account is convenient and dangerously broad. Give support tools scoped capabilities, require a ticket or reason where appropriate and preserve both operator and effective tenant identity. Silent impersonation destroys accountability.
Support should diagnose from safe metadata before viewing customer content. Break-glass access needs strong authentication, limited duration, alerts and review. The mechanism must be usable during an incident or staff will create informal bypasses.
Audit and telemetry systems also contain tenant information. Decide whether customers can view their own events and how operators query across tenants without exposing data in dashboards or high-cardinality metrics.
Tenant lifecycle is a distributed workflow
Onboarding may provision databases, storage, identity configuration, domains and initial administrators. Make it idempotent and observable; a partially created tenant should resume or roll back safely.
Offboarding needs retention, export, deletion and billing policy. Disabling login is not deletion. Find data in primary stores, replicas, search, caches, exports, telemetry and backups, then preserve only what policy requires.
Tenant moves between shards, stamps or regions require a period of routing and data coordination. Stable tenant identity should not encode physical location. Rehearse moves before capacity pressure turns them into emergency engineering.
Production isolation checklist
- Resolve tenant context from authenticated membership.
- Authorise resources, not tenant IDs alone.
- Select isolation per compute, data and storage boundary.
- Scope queries, constraints, caches and locks.
- Carry validated tenant context into queued work.
- Apply fairness and quotas to shared resources.
- Version tenant configuration without code forks.
- Control support access and preserve effective identity.
- Automate onboarding, migration and deletion.
- Test cross-tenant denial across every data path.
Multi-tenancy is successful when isolation is a system property rather than developer memory. The architecture should make the safe tenant-scoped path natural and every cross-tenant operation exceptional, explicit and auditable.