WhollySoftware
Back to blogWeb

Building a Multi-Tenant SaaS Dashboard Architecture

Wholly Software TeamApril 15, 20256 min read
Building a Multi-Tenant SaaS Dashboard Architecture

For a B2B SaaS client building an operations dashboard, the initial architecture decision was shared database, shared schema, with every table carrying a tenant_id column and application-level filtering on every query. It's the cheapest multi-tenancy model to build and scale, and it's the one we recommend by default for early-stage products where infrastructure cost matters more than isolation guarantees.

It's also the model most exposed to a specific class of bug: a developer forgets a WHERE tenant_id = ? clause on one query, and suddenly one tenant's dashboard is showing another tenant's data. This happened once in staging, caught by an automated test, but it was close enough to a real incident that we changed the pattern. We moved all tenant-scoped queries behind a query builder wrapper that injects the tenant filter automatically based on the authenticated request context, rather than trusting every hand-written query to remember it.

For Postgres specifically, we later layered on row-level security policies as a second line of defense — even if application code forgets the filter, the database itself refuses to return rows outside the current tenant's context, set via a session variable at the start of each request. This adds a small per-query overhead, but it turns a class of bug that used to be a silent data leak into a query that just returns nothing, which is a failure mode we can live with.

For a subset of enterprise customers on this same platform who required stronger data isolation guarantees for compliance reasons, we moved them to schema-per-tenant within the same Postgres instance — same codebase, separate schemas, connection routed based on tenant on each request. It's more operational overhead, migrations now run per-schema, but it was cheaper than dedicated database-per-tenant while satisfying the isolation requirement those specific contracts needed.

The dashboard itself — the frontend layer — didn't change much across these backend shifts, which was the point of keeping tenant isolation as a data-layer concern rather than baking assumptions about it into UI components. That separation is what let us support three different isolation models for different customer tiers without three different frontends.

SaaSArchitectureMulti-tenancyPostgreSQL
Building a Multi-Tenant SaaS Dashboard Architecture — Wholly Software