What Building a Multitenant ERP Taught Me About SaaS Architecture
Tenant isolation sounds like a database decision. It's actually an application-wide discipline. Lessons from shipping a multitenant ERP.

Multitenancy is usually explained as a schema strategy: shared database with a tenant_id, or schema-per-tenant, or database-per-tenant. In practice, the database is the easy part.
Isolation must survive every layer
The hard lessons came from everywhere except the data layer:
- Caching — a cache key without tenant scoping is a data breach waiting to happen
- Background jobs — Celery/queue workers must carry tenant context explicitly; there is no HTTP request to infer it from
- File storage — paths, buckets and signed URLs all need tenant boundaries
- Logging — logs leak. Aggregate them per tenant or scrub them.
Modularity pays for itself
We organized the system as modular business domains (inventory, billing, HR) with strict API contracts between them. When requirements shifted per client segment, modules could diverge without dragging the whole monolith along.
The agent angle
Embedding an LLM agent into ERP workflows raised the stakes: the agent's retrieval scope had to be tenant-bounded by construction, not by prompt instructions. Prompt-level isolation is not isolation.
FAQ
What is multitenant isolation in SaaS?
Multitenant isolation guarantees that one tenant can never access another tenant’s data or observe its activity. It must hold at every layer: database queries, cache keys, background jobs, file storage, logs, and LLM retrieval scopes.
Is schema-per-tenant better than a shared tenant_id column?
Neither is universally better. A shared table with tenant_id scales cheapest and simplifies migrations; schema-per-tenant gives stronger isolation for compliance-heavy clients at higher operational cost. The database choice matters less than enforcing tenant context in every application layer.
How do you secure an LLM agent inside a multitenant system?
The agent’s retrieval scope must be tenant-bounded by construction — enforced in the data layer and query routing, never by prompt instructions alone. Prompt-level isolation is not isolation.