Django’s Multi-database Routing: The Ultimate Guide to Scaling Your App
1. Introduction: Why Multi-DB Routing?
This issue with single-DB Django apps
Most Django apps start with a single database. But once traffic builds up:
- Read-heavy apps (blogs and dashboards) would suffer unacceptably from the loads of queries.
- Write-heavy ones (e-commerce, analytics) suffer from locking issues.
- Multi-tenant SaaS apps need to lock away data between customers.
The Solution: Multi-Database Routing
It can allow in Django
- Read/Write Splitting → Writes go into primary, reads go into replicas.
- Multi-Tenant Isolation → Each tenant uses its own database.
- Legacy DB Integration → From outside, connect to your database seamlessly.
2. How Django Handles Multiple Databases
Key Components
- DATABASES Setting—Define multiple DB connections.
- Database routers—Decide which DB a query goes to.
- using() Method—Manually choose a DB for a query.
Example settings.py
DATABASES = {
'default': { # Primary (for writes)
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'primary_db',
},
'replica': { # Read replica
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'replica_db',
},
}
3. Setting Up Multi-DB in Django
Step 1: Configure Databases
- Have multiple DBs in the settings.py (as shown above).
Step 2: Create Database Router
class ReadReplicaRouter:
def db_for_read(self, model, **hints):
return 'replica' # All reads go to replica
def db_for_write(self, model, **hints):
return 'default' # All writes go to primary
Step 3: Add Router to Settings
DATABASE_ROUTERS = [‘path.to.ReadReplicaRouter’]
4. Database Routing Strategies
A. Read/Write Splitting
- Best for: Blogs, analytics dashboards.
- Router Logic:
def db_for_read(self, model, **hints):
return random.choice([‘replica1’, ‘replica2’]) # Load balancing
B. Multi-Tenant (One DB per Tenant)
- Best for: SaaS apps (e.g., CRM, project tools).
- Router Logic:
def db_for_read(self, model, **hints):
tenant = get_current_tenant()
return tenant.database_name
5. Real-Life Scenarios & Performance Boosts
Case Study: Scaling an E-Commerce App
Before Use Case: One DB served on an average basis, under load, with a 500-millisecond response time.
After Use Case: One primary DB with two replicas served in an average manner, with a response time of 150 milliseconds.
Benchmarks
Set up | Average Query Time | Requests per Second |
Single DB | 500 ms | 100 |
Multi-DB | 150 ms | 350 |
6. Pitfalls & Best Practices
Common Mistakes
- Replication Lag—Reads may get stale data. Fix: Use sticky sessions.
- Transaction Issues—Writes in transactions must stay on one DB.
Best Practices
- Monitor Replication Delay (e.g., PostgreSQL pg_stat_replication).
- Use atomic() Wisely – Avoid cross-db transactions.
7. Conclusion
When to Use Multi-DB Routing?
- Read-heavy apps
- Multi-tenant SaaS
- Legacy DB integration
Final Thoughts
Django’s multi-db routing is underused but powerful. It’s simpler than Channels and more impactful than Signals for scaling.