Is Django Multi-Tenant Worth It? A Developer’s Tale of Trials, Errors, and Rediscovery

Marlon MachariaMarlon Macharia
6 min read

As a developer, I love challenges. But there’s a certain kind of challenge that makes you question your life decisions, especially when it comes to multi-tenancy in Django. It seemed so simple at first—build an app that can serve multiple clients, each with its own data and functionality. Easy, right? Not so fast. The journey to implement a global authentication system where users could seamlessly switch between tenants without having to re-authenticate felt like climbing Mount Everest. My chosen path became a series of obstacles that took me deep into the world of database schemas, authentication nightmares, and ultimately, the discovery that sometimes, the best solution is the one that just works.

Let me walk you through my struggle, how I tried to solve it, and why—despite all my scars—I still believe that Django’s multi-tenant approach is worth exploring...just not today.

The Great Multi-Tenant Dream

The idea of multi-tenancy is simple in theory: you want to serve multiple customers (tenants) with the same application, while keeping their data separate. Think SaaS products like Slack, where every workspace operates independently but under the same app.

I was fascinated by this. In my case, I wanted to go one step further—allowing users to belong to multiple tenants and switch between them without being forced to log in again. So, if John Doe works for both Company A and Company B, he could switch between these tenants without needing to re-authenticate every time. It sounded simple on paper, but in practice, it turned into a monster.

Attempt #1: The Multi-Database, Multi-Schema Approach

Initially, I gravitated towards the idea of using separate databases or schemas for each tenant. I experimented with Django packages like django-tenant-schemas and django-tenants, and I thought I had found the right solution. These packages make it relatively easy to isolate each tenant’s data by creating separate schemas within the same database or using multiple databases. It’s a neat way to keep data clean and separated.

Then came the authentication issue.

  • How could I allow users to access multiple tenants and switch seamlessly between them?

  • How could I avoid re-authentication every time a user switched to a different tenant?

I stumbled upon django-tenant-users, which seemed like the magic bullet for handling global authentication. It promised to allow users to be associated with multiple tenants, but that’s where my troubles began.

The Nightmare of Global Authentication

I can’t count the number of hours I spent trying to make django-tenant-users work for my use case. Debugging this package was like walking through a fog—half the time, I wasn’t sure where I was going, and the other half, I was just hoping to not fall into a deep pit.

The documentation wasn’t always clear, and making the authentication system work with multiple tenants felt like trying to solve a puzzle where the pieces didn’t quite fit together. I tried custom middleware, session hacks, and even considered writing my own solution. Each time, I was met with more bugs, unexpected behavior, and a creeping sense of frustration.

In my mind, I had this vision of a perfect, multi-tenant app where users could switch tenants as smoothly as switching browser tabs. But in reality, I spent more time trying to figure out how to switch users between tenants without re-authentication than actually building features.

The complexity of isolating tenant data and maintaining global authentication started to feel like more work than the benefits it promised. I realized I needed a simpler, more reliable approach that wouldn’t break my soul.

Seeing the Sunshine: The 1 DB, Shared Schema Approach

At some point, I had to make a decision: continue fighting this battle or pivot to something simpler. That’s when I stumbled upon the 1 DB, shared schema approach. Rather than dealing with multiple schemas or databases, this approach uses a single shared schema for all tenants, typically with a tenant_id field to distinguish between them.

It felt almost too simple, but it worked like a charm. No more multi-schema management, no more complex session juggling, and no more authentication madness. Users could belong to multiple tenants, and switching between them became as easy as flipping a switch in the database. The simplicity of using one database with tenant-specific filtering in queries made things feel sane again.

Here’s the real beauty: with the shared schema approach, I could focus on caching to optimize the performance and minimize any inefficiencies. By integrating Redis, I managed to cache tenant-specific queries, which helped reduce database hits and sped up the overall performance. Redis became my saving grace. With proper caching in place, the query times between tenants were significantly reduced, and the app finally started to feel responsive.

The Pros and Cons of Each Approach

While the 1 DB, shared schema approach ultimately worked for me, it wasn’t without trade-offs. Let’s take a look at the pros and cons of both approaches:

Multi-Database, Multi-Schema Approach (Isolated Tenants)

Pros:

  • Stronger data isolation between tenants.

  • Better scalability for large tenant data volumes.

  • Reduced chance of tenant data being accidentally shared or leaked.

Cons:

  • Much more complex to set up and manage.

  • Global authentication across tenants is a challenge.

  • Potentially higher costs with multiple databases/schemas.

  • Debugging can be a nightmare (trust me).

1 DB, Shared Schema Approach (Shared Tenants)

Pros:

  • Simpler to set up and maintain.

  • Easier to manage global authentication.

  • Lower operational costs—just one database.

  • Easier to implement caching strategies like Redis to improve performance.

Cons:

  • Tenant data is more prone to accidental leaks if not careful with query filtering.

  • Less isolation means potential performance issues as the number of tenants grows.

  • Scaling could become a challenge with high volumes of tenant-specific data.

What’s the Right Approach?

After my experience, I realized that there’s no one-size-fits-all solution for multi-tenancy in Django. The multi-database, multi-schema approach is great for apps that require strict tenant data isolation and can handle the complexity of setup. But for me, the 1 DB, shared schema approach allowed me to focus on what really mattered—building features that my users needed without getting bogged down by complex authentication systems.

Would I go back and try multi-tenancy again? Maybe. In another lifetime, when I have more patience (and more coffee). But for now, I’ll stick with what works and keeps me sane.

The Takeaway

In the end, my journey with Django multi-tenancy was a humbling one. It taught me that the most complex solution isn’t always the best, and sometimes simplicity wins. Multi-tenancy, when done right, can be a powerful tool, but it’s not always worth the cost in time and complexity if it doesn’t align with your project’s needs.

So, is Django multi-tenancy worth it? Absolutely—just pick the approach that best fits your needs and long-term goals. And if you’re anything like me, sometimes the solution that works today is the one that keeps you from losing your mind.

0
Subscribe to my newsletter

Read articles from Marlon Macharia directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Marlon Macharia
Marlon Macharia

I’m Marlon, a backend software engineer with a passion for solving complex tech challenges and building scalable systems. I enjoy exploring entrepreneurship, coding, and the evolving world of technology.