Essay · Published · 6 min read

One Platform, Many Businesses: The Real Work of Multi-Tenancy

Multi-tenancy is not a tenant_id column. It's a promise you have to keep in every query, every export, every AI-generated recommendation — and one leak anywhere makes the whole promise fiction.

  • Multi-tenancy
  • Architecture
  • Data Isolation
  • Enterprise Software

The first time I heard multi-tenancy described casually, it was summarised as "add a tenant ID column and filter by it." That description isn't wrong exactly, in the way "cooking is heating food" isn't wrong. It's just missing everything that makes the thing hard.

I got a real education in this while directing the build of Multi-tenant Commerce, a platform where separate brands run their own storefronts, catalogues and seller operations on one shared architecture. The tenant ID column was the easy five percent. The other ninety-five percent was making sure that column's promise held everywhere — in every query, every report, every cached page, every background job — because a multi-tenant system isn't multi-tenant until you can prove the isolation holds under every condition, not just the common ones.

What a leak actually looks like

Multi-tenant failures rarely look dramatic. Nobody breaks in. What actually happens is quieter and, in some ways, worse: a report-generation job forgets to scope its query by tenant, and for three seconds one business sees a number that belongs to a competitor. A cache key gets built from a record ID without the tenant prefix, and two tenants' product pages briefly serve each other's content. An analytics dashboard aggregates "all recent orders" without noticing it just aggregated across every tenant on the platform.

None of these require malicious intent. They require one developer, on one afternoon, writing one query the normal way instead of the tenant-scoped way — and the bug sits invisible until the wrong two tenants happen to collide. This is why I've come to treat multi-tenant isolation less like a feature and more like a discipline that has to be checked, actively, on every single feature that touches data, for the lifetime of the platform.

Where the real work lives

Building Multi-tenant Commerce taught me to break the isolation problem into layers, because "isolation" as a single word hides how many different things actually need to be separated:

Data boundaries. Every table that holds tenant-scoped data needs enforcement at the database layer, not just in application code that might forget. Row-level security, or its equivalent, should make it structurally difficult to write a query that accidentally spans tenants — not just a matter of remembering to add a WHERE clause.

Users and roles. A person's identity and permissions exist within a tenant. Someone who's an administrator for one brand should have zero implicit standing in another, even though they're using the same login system and the same underlying platform.

Configuration and branding. Each tenant needs its own look, its own settings, its own feature flags — visible customisation that's actually easy to get right, because it's the part users notice immediately if it's wrong.

Operational isolation. This is the layer people forget most often. A slow query from one tenant's unusually large catalogue shouldn't degrade performance for every other tenant on the platform. A background job processing one tenant's data shouldn't be able to accidentally queue work against another tenant's records.

Provisioning and lifecycle. Onboarding a new tenant, suspending one, and — carefully — offboarding one are all events that touch every layer above, and each needs its own tested path rather than being treated as a manual, ad hoc process someone does once and never again.

Applying the same discipline to an ERP

An ERP raises the stakes on all of this compared to a storefront, because the data it holds is more sensitive and the cost of a leak is higher — financial records, supplier contracts, payroll-adjacent information, not product catalogues. NxSync ERP's tenant model is being designed with the same layered discipline that Multi-tenant Commerce forced me to internalise: enforcement at the data layer rather than trusting application code to remember, tenant-scoped authority for any AI-assisted recommendation or action, and provisioning treated as a first-class, tested workflow rather than an afterthought.

I want to be precise here again about what's established and what's still being built. The design commitment — isolation enforced structurally, not just by convention — is set. The specific implementation across every module of an ERP-scale platform is a larger and longer undertaking than a commerce platform, and it is still in progress. I'm not claiming NxSync ERP's tenant isolation has been independently audited or proven under adversarial conditions. I'm describing the standard it's being built against and the real experience that standard comes from.

Why "just use a separate database per tenant" isn't the easy escape it sounds like

Whenever I describe this problem to someone technical for the first time, the same suggestion comes back: why not sidestep the whole isolation problem by giving each tenant a fully separate database? No shared tables, no WHERE clause to forget, no structural leak possible.

It's a reasonable instinct, and for a platform with a handful of large tenants it can be the right call. But it trades one hard problem for a different hard one. A separate-database-per-tenant model means every schema migration has to run correctly across every tenant's database, every time, with no tenant silently left on an old schema version. It means your operational tooling — backups, monitoring, capacity planning — now has to work across an unbounded and growing number of independent databases rather than one well-understood one. And it means cross-tenant features, the moment the business genuinely needs one (aggregate reporting for an internal team, say), require querying across every tenant's database individually rather than one shared, properly scoped table.

Neither approach — shared schema with enforced row-level isolation, or genuinely separate databases — is free. The choice is about which set of hard problems you'd rather own, and for an ERP-scale platform with many small-to-mid-sized tenants rather than a few enormous ones, shared infrastructure with structurally enforced isolation is the trade I'd make again: it keeps operational complexity from growing linearly with tenant count, at the cost of needing genuine discipline in how every query gets written.

The part that stays uncomfortable

Here's the honest limitation: even with every layer above done well, multi-tenancy is never a problem you solve once. It's a problem you keep solving, feature by feature, for as long as the platform is being developed — because every new feature is a new opportunity for someone to write the query the easy way instead of the tenant-scoped way. The best defence I know is automated tests that specifically try to break isolation — write a test that attempts to read tenant B's data while authenticated as tenant A, and run it on every change, not just at launch. That's a testing discipline, not a one-time architectural decision, and it's the piece I trust the least to survive schedule pressure without active vigilance. I'd rather say that plainly than imply a data model, once well designed, takes care of itself.

View the full NxSync ERP series

Mohammed Umair builds businesses and the systems they run on — across smart infrastructure, international trade and enterprise software. More about him.