Multi-Tenant SaaS Architecture in Django & Vue - KEHEM IT
← Back to Studio Notes

How to Build a Multi-Tenant SaaS Architecture in Django & Vue

Learn how to architect scalable multi-tenant SaaS applications using Django and Vue 3, covering schema isolation, shared databases, subdomains, and security.

KEHEM / Studio Notes
  KEHEM

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_id foreign key. Queries always filter by tenant_id.
  • Pros: Cheapest hosting footprint, easiest database migrations, simple global analytics across tenants.
  • Cons: Risk of data leakage if a developer forgets a tenant_id filter; 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 the public schema.
  • 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).

Comparing the Three Approaches Honestly

DimensionShared schemaSchema per tenantDatabase per tenant
Isolation strengthLogical (application-enforced)Strong (engine-level)Strongest (physical)
Risk of cross-tenant leakHighest — one missing filterVery lowEffectively none
Migration time at 500 tenantsSecondsMinutesHours
Migration time at 5,000 tenantsSecondsHours (needs orchestration)Days
Per-tenant restoreHardEasyTrivial
GDPR export / deletionRequires careful scopingpg_dump one schemaDump one database
Cross-tenant analyticsEasyRequires aggregation across schemasDifficult, needs a warehouse
Hosting cost at 100 tenantsLowestLowHigh
Onboarding a new tenantInstantInstant (create schema)Minutes (provision DB)
Practical ceilingTens of thousandsHundreds to low thousandsHundreds

The trade-off is consistent across all three: stronger isolation costs you operational flexibility. Schema-per-tenant buys near-complete isolation while keeping migrations automatable, which is why it suits B2B software with dozens to a few thousand customers. Row-level isolation stays competitive when you have many small accounts and need cross-tenant reporting. Database-per-tenant is for when a contract requires it and you can staff the operations.

One further consideration that rarely appears in comparisons: cost per tenant. Row-level isolation lets a single small database serve thousands of accounts. Schema-per-tenant and database-per-tenant both mean that adding customers adds operational work, and at a certain scale you need tooling to run migrations across every schema on a schedule. Plan for that tooling in the same sprint as the tenth tenant, not the thousandth.

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 $\rightarrow$ routes to Acme's schema. * beta.yourproduct.com $\rightarrow$ routes to Beta's schema. * app.yourproduct.com $\rightarrow$ routes to the public shared schema.

Two practical requirements follow from subdomain routing. You need a wildcard DNS record and a wildcard TLS certificate, both of which should be provisioned on day one rather than after the first customer signs. And you should decide early whether tenants can use a custom domain — that means certificate provisioning per domain, which changes your infrastructure setup considerably.

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)

The critical detail is what happens when no tenant matches. A request to an unknown subdomain should fail loudly — a 404 or a redirect to signup — never silently fall through to the public schema, where it might serve the wrong data or create records in the wrong place.

3. Background Tasks Are Where Multi-Tenancy Breaks

This is the single most common multi-tenancy bug, and it does not appear in development because everything is tested in one request context.

Celery workers do not have a request, so they have no tenant. Every task must be told which tenant to operate on, and must switch the schema before touching the database:

@shared_task
def send_weekly_report(tenant_id: int, user_id: int):
    tenant = Tenant.objects.get(pk=tenant_id)
    with tenant_context(tenant):          # switches the schema for this task
        user = User.objects.get(pk=user_id)
        report = build_report(user)
        email_report(user, report)

Without tenant_context, that task queries whichever schema the worker last used — often another customer's. If you take one thing from this article, take this: test your background tasks with two tenants seeded, and assert that each task only ever touches its own data.

Defence in Depth: Never Rely on One Mechanism

Even with schema isolation, add a second layer. A custom manager that refuses unscoped queries, or an assertion in your test suite that every data model has a tenant-aware base class, prevents the slow drift where a new model is added without the right structure.

Practical measures:

  • A base model for tenant-scoped entities, so new models inherit the pattern by default.
  • Tests that assert isolation explicitly — create two tenants, write as tenant A, query as tenant B, assert the result is empty. Put these in CI.
  • A production smoke check that runs a similar assertion against staging after every deploy.
  • An audit log recording tenant ID with every write, so if something does go wrong you can determine the blast radius rather than guessing.

Frontend Architecture with Vue 3 & Pinia

On the frontend, Vue 3 handles multi-tenancy through clean state management and dynamic API base URLs.

  1. Subdomain Context: Vue extracts the current tenant identifier from window.location.hostname.
  2. Global Tenant Store: Pinia stores the active tenant settings, branding themes, and permissions.
  3. Axios/Fetch Interceptor: The HTTP client automatically passes tenant context and JWT credentials with every API request.

Two frontend details worth planning for. Branding per tenant — logos, colours and email sender names — is usually the first thing B2B customers ask for after launch, so build the settings model early even if the UI comes later. And cache the tenant config rather than fetching it on every route change, or every page load will pay a round trip before rendering.

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.

Four more that enterprise buyers ask about specifically:

  • Data residency. EU customers increasingly require their data stored in the EU. This is an infrastructure decision made before launch, not a config change afterwards.
  • Sub-processor transparency. A published list of the third parties that touch customer data — hosting, email, payments, monitoring.
  • Session and token policy. Token lifetimes, forced logout, and revocation on password change or account removal.
  • Penetration test evidence. An annual third-party test with a summary available to prospects shortens enterprise security reviews considerably.

Cost and Timeline Implications

ScopeTypical timeline
Single-tenant app with tenant_id added2-3 weeks (if done at the start)
Multi-tenant from the start, schema-basedAdds 1-2 weeks to a standard MVP
Retrofitting multi-tenancy onto a single-tenant app6-16 weeks, with data migration risk
Enterprise tier: SSO, audit logs, custom domainsAdds 4-6 weeks

The last two rows are the argument for deciding early. Retrofitting tenancy costs several times what building it correctly costs, and it carries genuine data-integrity risk during migration. Enterprise features can be delayed; the tenancy model cannot.

Key Takeaways

  1. Choose your isolation model early: Migrating from row-level to schema-level multi-tenancy later is painful and risky.
  2. Use PostgreSQL schemas for B2B: They offer the ideal sweet spot between strict enterprise security and developer maintenance sanity.
  3. Keep the frontend decoupled: Vue 3 communicates with Django over clean REST/GraphQL APIs, keeping UI logic independent of database partitioning.
  4. Give every background task an explicit tenant context — this is where isolation silently fails.
  5. Test isolation from the attacker's perspective and run those tests in CI on every commit.

Related reading: RBAC is the security layer multi-tenancy makes harder; PostgreSQL vs MySQL covers schema-per-tenant trade-offs; and microservices vs monolith explains why not to split this system up too early. 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.

Building multi-tenant and unsure how to isolate tenants? Talk to us before you pick a schema strategy.

Have a project in mind?

KEHEM designs and builds thoughtful websites, SaaS products, and business systems.

Talk to KEHEMExplore Services