Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

Multiple DBs: archtechx / tenancy

Premium
9:00

Before switching to the setup of multiple databases, let's talk about WHY you would want to do that.

I got this question from a few people on Twitter:

A multi-database setup means one database per customer/company/organization. Yes, it means managing 100s of databases if you have 100s of companies using your application.

Sounds overwhelming, doesn't it? But not necessarily.

The most common use case for this is the BUSINESS needs by those companies to store data separately from other companies using your application. Usually for privacy and legal reasons.

For example, if you are Microsoft, you would probably want to minimize the risks that some of your internal data would become visible to Apple or Google?

Also, there may be technical architectural reasons to separate the database, such as potential individual scaling or managing resources for each tenant based on their own requirements.

However, it also comes with additional complexity and more work to set up and manage multiple databases.

Let me try to summarize the pros and cons of this multi-database approach.

Advantages of multiple databases:

  1. More security and privacy, sometimes required legally. More extensive protection from data leaks.
  2. Ability to export data and make backups separately.
  3. Potential performance gains: queries work faster because the database wouldn't need to touch other databases.
  4. Ability to separate virtual/physical servers and scale individual tenant resources when needed.
  5. If something wrong happens with data, it's easier to roll back or recover the data for one database without touching others.

Disadvantages:

  1. Complexity to set up and maintain, especially the DB migrations. Connection names are used everywhere, still with a risk of accidentally connecting to the wrong database.
  2. Harder to add new features and deploy changes because you need to execute migrations to multiple databases.
  3. Harder/impossible to query data from multiple tenants if grouped reports are needed.

In short, you need a multi-database setup only if it's actually the requirement either from the clients or from yourself as an architectural decision for scalability.

In most cases, for smaller projects, one database is totally fine.

That said, if you still want to dive into that more complex setup, let's get familiar with the approach and the tools.


Installation and Configuration

Let's first create the multi-database and multi-tenancy setup with the package stancl/tenancy. Some of the code from earlier for this package from a single database, like installation, will be repeated, and then we'll move deeper.

The initial setup is the same Laravel Breeze with two CRUDs: Projects and Tasks.

So, let's install the package.

composer require stancl/tenancy
php artisan tenancy:install

bootstrap/providers.php:

return [
App\Providers\AppServiceProvider::class,
App\Providers\TenancyServiceProvider::class,
];

IMPORTANT NOTICE: Version 3 doesn't support the database session driver. The easiest change would be to file as a session driver.

And now, here is the first difference between single and multiple databases. The DB_CONNECTION value should be...

The Full Lesson is Only for Premium Members

Want to access all of our courses? (29 h 14 min)

You also get:

54 courses
Premium tutorials
Access to repositories
Private Discord
Get Premium for $129/year or $29/month

Already a member? Login here

Comments & Discussion

SS
sopheary sun ✓ Link copied!

Thank you so much for this course. I was wondering if you could extend the course for integrate with package with spatie-laravel-permission and laravel-websocket. How to manage cache, queue, etc for tenanats.

PK
Povilas Korop ✓ Link copied!

For now, sorry, this is not in plans. I guess this is a question towards the package of stancl/tenancy, so you should read its docs or ask on their GitHub, or look for tutorials online on those topics.

SS
sopheary sun ✓ Link copied!

I have followed your above instruction and I got this error "Tenant could not be identified on domain sr". I created two tenancies as sr.local.test and pp.local.test. I hosted them with WAMP. I can access local.test domain but not the subdomains. I use the below route on tenant.php Route::middleware([ 'web', InitializeTenancyBySubdomain::class, PreventAccessFromCentralDomains::class, ])->group(function () { Route::get('/', function () { dd(\App\Models\User::all()); return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id'); }); });

PK
Povilas Korop ✓ Link copied!

Sorry, I'm not familiar how WAMP works with domains and subdomains, so it's hard for me to comment or debug for you. In my videos and testing, I'm using Laravel Valet on my Macbook, which does (sub)domains automatically.

M
MimisK ✓ Link copied!

hmm. I don't understand how the Redirect will be made to the subdomain on the login.

KA
Kashif Amin ✓ Link copied!

Hi, Thanks for this amazing course. I want to ask if we have a high traffic on each of our tenants, will the swithcing between respective database slow down?

PK
Povilas Korop ✓ Link copied!

Interesting question. The switch itself doesn't really cost much time/resources, it's more about querying from that database.

KV
Kailash Vele ✓ Link copied!

How to write tenants routes in web.php in stancl tenancy?

MS
mahdi sahib ✓ Link copied!

Hi, I got ( this page has expired ) 419 | PAGE EXPIRED when try to login tenant i use filament admin panel

M
Modestas ✓ Link copied!

This is due to CSRF token failure. I'm not sure what caused it as you did not share any code. Please check that the login form is correctly implemented

K
kaleemullah ✓ Link copied!

Can main administrator switch to different tenant in this package?

SB
Shadyar Bzhar Othman ✓ Link copied!

Thanks, if I'm using api do I need to change anything from bootstrap.app? or this one is okey?

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__ . '/../routes/web.php',
        api: __DIR__ . '/../routes/api.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        //
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();
C
CONSTANTlNE ✓ Link copied!

For those who come from Windows environment and can't use subdomains like "subdomainname.tenancyapp.test"

you have to manually add each subdomain into hosts file :

C:\Windows\System32\drivers\etc\hosts

Like : 127.0.0.1 subdomainname.tenancyapp.test

Im using Laravel Herd , windows 11 , worked for me and hope it would work for you too..

if anyone knows more "elegant way" please comment ...

M
Modestas ✓ Link copied!

Sadly, there is no better way, unless using another tool to fake the DNS. But that comes with setup headache, so better off to use Herd for that :)

HA
Harrison Amaghu Idornigie ✓ Link copied!

One way is to tell Laravel to use the central database connection. This can be done in two ways: setting a $connection property or using a CentralConnection Trait from the package on the Model.

What is the other way? How can i user the users table in the tenant database?

DV
Daniele Vitiello ✓ Link copied!

Hi, i'm using herd (https) and vue stack with inertia. When is performed return redirect('http://' . $request->subdomain . '.'. config('tenancy.central_domains')[0] . route('dashboard', absolute: false)); there's a CORS issue Access to XMLHttpRequest at 'https://daniele.awp_management_3.test/dashboard' (redirected from 'https://awp_management_3.test/register') from origin 'https://awp_management_3.test' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Using Inertia::location, instead, I get 419 page expired. How can i resolve issue locally and in production?