django-tenants

Building Enterprise-Grade SaaS with Django

Very few know how to build a SaaS platform that safely serves hundreds or thousands of companies from a single system.

The difference is not features. It is architecture.

In this article, I will focus on one critical concept used by real SaaS platforms: schema-based multi-tenancy using Django and PostgreSQL.

This guide is intentionally minimal and educational.
No advanced tooling. No distractions. Just the core ideas

Why Multi-Tenancy Is Fundamental to SaaS

Imagine you are building a project management product.

You onboard 200 companies.

Do you:

  • Deploy 200 applications?
  • Maintain 200 databases?
  • Run migrations 200 times?

That approach quickly becomes impossible.

A SaaS platform must:

  • Use one codebase
  • Use shared infrastructure
  • Still keep customer data fully isolated

This is exactly what multi-tenancy provides.

The Three Ways to Implement Multi-Tenancy

1. Shared Tables with Tenant ID

All tenants share the same tables. Data is filtered using a tenant_id column.

This is simple, but dangerous.
A single missing filter can expose data across tenants.

This approach does not scale safely.

2. Shared Database, Separate Schemas (Recommended)

Each tenant gets:

  • The same PostgreSQL database
  • A separate schema

Django connects to the correct schema per request.

This gives:

  • Strong isolation
  • Clean Django ORM usage
  • High performance
  • Simple operations

This article focuses on this approach.

3. Separate Database per Tenant

Each tenant has a dedicated database.

This offers maximum isolation but adds major operational complexity.
Most SaaS platforms do not need this.

Why Schema-Based Multi-Tenancy Works

Isolation at the Database Level

Schemas are enforced by PostgreSQL itself.

Even if the application code is incorrect, the database prevents cross-tenant access.
Security does not depend on developer discipline.

Scales Without Rewrites

You can:

  • Add tenants without new databases
  • Scale application servers horizontally
  • Apply migrations consistently

The architecture remains stable as the business grows.

Django Code Remains Clean

You write normal Django queries:

Project.objects.all()

Django-tenants ensures the query runs in the correct schema automatically.

No tenant_id fields everywhere.
No custom query filters.

How Tenant Resolution Works

A simplified request flow:

  1. User opens acme.example.com
  2. Middleware extracts acme
  3. Tenant is found in the public schema
  4. Database connection switches schema
  5. ORM queries run inside that schema
  6. Response is returned

Every request is isolated by default.

Data Layout Strategy

Public Schema

Contains platform-level data:

  • Tenants (companies)
  • Domains or subdomains

This answers the question: who is the customer?

Tenant Schemas

Each tenant schema contains:

  • Projects
  • Tasks
  • Comments
  • Files
  • Activity logs

This answers the question: what belongs to this company?

Essential Libraries

This blog intentionally uses only the core requirements.

Django

pip install django

The main web framework.

django-tenants

pip install django-tenants

Handles:

  • Schema creation
  • Schema switching
  • Tenant-aware migrations

PostgreSQL Driver

#for linux 
pip install psycopg2-binary

#for Windows
pip install psycopg2

Required for PostgreSQL schema support.

Essential Commands

Run shared (public schema) migrations:

python manage.py migrate_schemas --shared

Run migrations for all tenant schemas:

python manage.py migrate_schemas

Create a tenant:

python manage.py create_tenant

Create a superuser:

python manage.py createsuperuser

Common Mistakes Beginners Make

  • Forgetting the tenant context in the background logic
  • Assuming Django ORM alone guarantees isolation
  • Caching tenant data without tenant keys
  • Skipping migration testing across schemas
  • Not understanding the public vs tenant schema separation

Most of these mistakes appear only after the system grows.

Final Thoughts

Enterprise SaaS is not about complexity.
It is about correct boundaries.

Schema-based multi-tenancy gives you:

  • Strong data isolation
  • Predictable scaling
  • Clean Django code
  • Long-term stability

With just Django, django-tenants, and PostgreSQL, you can build a foundation capable of serving real businesses safely.

Everything else can be added later.

Architecture, however, is very hard to fix later.

Build it right from day one.

If you want next, I can:

  • Turn this into a step-by-step tutorial series
  • Add simple Django models for teaching
  • Write a tenant onboarding walkthrough
  • Prepare a clean project folder structure

Just tell me the next chapter.

Why This Matters

Schema-based multi-tenancy relies on hostnames to resolve tenants.
The domain resolution and middleware logic treat localhost them 127.0.0.1 as different hosts.

In development, tenant routing and schema switching are configured to work with localhost. Accessing the app via 127.0.0.1 bypasses this logic, causing tenant resolution to fail.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top