Building a multi-tenant SaaS application is one of the most critical architectural decisions a software team will make.
When building for B2B customers across the US, Europe, Canada, and Australia, data privacy, strict isolation, and performance under scale are not optional. You cannot afford a bug where Company A sees Company B's financial records or client contacts.
In this guide, we break down how to design and build a robust, scalable multi-tenant SaaS backend using Django and Django REST Framework paired with a modern Vue 3 frontend.
What Is Multi-Tenancy in SaaS?
Multi-tenancy is an architectural pattern where a single instance of a software application serves multiple distinct customer organizations (called tenants).
Each tenant has its own isolated data, configuration, user accounts, and billing, while sharing the underlying computational infrastructure, application logic, and database server.
3 Multi-Tenant Database Isolation Strategies
Before writing code, you must choose how tenant data is separated at the database layer. There are three primary patterns:
1. Shared Database, Shared Schema (Row-Level Isolation)
┌──────────────────────────────────────────────────┐
│ Table: Users, Invoices (tenant_id foreign key) │
└──────────────────────────────────────────────────┘
2. Shared Database, Separate Schemas (PostgreSQL Schemas)
┌───────────────────────┬──────────────────────────┐
│ Schema: tenant_apple │ Schema: tenant_microsoft │
└───────────────────────┴──────────────────────────┘
3. Database-per-Tenant (Isolated Databases)
┌──────────────────────┐ ┌────────────────────────┐
│ DB: tenant_1_db │ │ DB: tenant_2_db │
└──────────────────────┘ └────────────────────────┘
Strategy 1: Shared Database, Shared Schema (Row-Level Isolation)
- How it works: All data lives in the same tables. Every table includes a
tenant_idforeign key. Queries always filter bytenant_id. - Pros: Cheapest hosting footprint, easiest database migrations, simple global analytics across tenants.
- Cons: Risk of data leakage if a developer forgets a
tenant_idfilter; complex database backup/restore for a single client. - Best for: B2C apps and low-cost B2B SaaS with thousands of small accounts.
Strategy 2: Shared Database, Separate Schemas (PostgreSQL Schemas) — Our Recommended Standard
- How it works: Using PostgreSQL schemas, each tenant gets its own namespace (e.g.,
schema_acme_corp) inside the same physical database instance. Public tables (users, subscriptions, global config) sit in thepublicschema. - Pros: Complete data isolation at the DB engine level; zero risk of cross-tenant query contamination; simple per-tenant data exports (GDPR compliance).
- Cons: Migrations take longer as tenant count grows into thousands.
- Best for: Mid-market and Enterprise B2B SaaS in US, EU, and Australia.
Strategy 3: Database-per-Tenant
- How it works: Each customer has a completely separate PostgreSQL database.
- Pros: Ultimate security, compliance, and dedicated hardware provisioning.
- Cons: High infrastructure maintenance and hosting costs.
- Best for: High-ticket enterprise software (fintech, healthcare, government).
Implementing Schema Multi-Tenancy in Django
In Django, libraries like django-tenants make PostgreSQL schema-based isolation straightforward and reliable.
1. Tenant Routing via Subdomains
Tenants are resolved automatically from the request hostname: * acme.yourproduct.com $ ightarrow$ routes to Acme's schema. * beta.yourproduct.com $ ightarrow$ routes to Beta's schema. * app.yourproduct.com $ ightarrow$ routes to the public shared schema.
2. Tenant Middleware
Django middleware inspects the request host, finds the matching tenant model, and dynamically switches the database connection cursor to the tenant's schema:
# Conceptual Tenant Middleware
class TenantMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
hostname = request.get_host().split(':')[0]
tenant = Tenant.objects.filter(domain=hostname).first()
if tenant:
connection.set_tenant(tenant)
request.tenant = tenant
return self.get_response(request)
Frontend Architecture with Vue 3 & Pinia
On the frontend, Vue 3 handles multi-tenancy through clean state management and dynamic API base URLs.
- Subdomain Context: Vue extracts the current tenant identifier from
window.location.hostname. - Global Tenant Store: Pinia stores the active tenant settings, branding themes, and permissions.
- Axios/Fetch Interceptor: The HTTP client automatically passes tenant context and JWT credentials with every API request.
Security & Compliance Checklist for B2B SaaS
When selling to European (GDPR), American (SOC2 / HIPAA), and Australian (Privacy Act) enterprises, ensure:
- Granular Role-Based Access Control (RBAC): Admin, Manager, Member, and Read-Only roles per organization.
- Audit Logging: Every create, update, delete, and export action must log the user ID, tenant ID, timestamp, and IP address.
- Single Sign-On (SSO): Support SAML 2.0 and Google Workspace / Microsoft Entra ID authentication for enterprise tiers.
- Data Portability & Purge: Provide 1-click JSON/CSV data export and automated GDPR right-to-be-forgotten deletion workflows.
Key Takeaways
- Choose your isolation model early: Migrating from row-level to schema-level multi-tenancy later is painful and risky.
- Use PostgreSQL schemas for B2B: They offer the ideal sweet spot between strict enterprise security and developer maintenance sanity.
- Keep the frontend decoupled: Vue 3 communicates with Django over clean REST/GraphQL APIs, keeping UI logic independent of database partitioning.
Need an experienced engineering team to build or refactor your SaaS platform? Talk to the engineers at KEHEM IT to design a rock-solid system from day one.
Have a project in mind?
KEHEM designs and builds thoughtful websites, SaaS products, and business systems.