Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

BMS51's avatar
Level 1

Laravel Multitenant solution.

Hello all,

I've been looking up information about multi tenancy (MT) in Laravel for the past few days. I've come across a whole bunch of heavy swiss army knife solutions that can handle almost anything. Yet they impact your codebase heavily. I've found a excellent video about multi tenancy by Mohamed Said.

"I will use one laravel install to service multiple tenants based on subdomain or domain names"

In this video he explains a lean and lightweight approach for MT in Laravel. His approach featured one database connection for the landlord and one for the tenants databases. This works if all databases for tenants are hosted on the same db server. Unfortunately most shared hostings create a new database on a different host, thus the entire connection needs to be changed per client. And here is where my issue starts.

So when a tenant visits his subdomain of the app the correct connection to the correct database must be established. The function below handles that:

I've created a separate .env file for eacht tenant (.env.tenant.tenantname). I use the Dotenv library to parse and load the needed variables from the custom .env file and fill the connection data with the values from the env variables. Then purge the 'tenant' connection and reconnect. I also try to change the APP_KEY for each tenant (in case they store some sensitive data).

public function configure()
{

    $dotenv = Dotenv::createUnsafeMutable(base_path(),'.env.tenant.'.$this->name);
    $dotenv->load();

    config([
        'database.connections.tenant.host' =>  $_ENV['TENANT_DB_HOST'],
        'database.connections.tenant.database' =>  $_ENV['TENANT_DB_DATABASE'],
        'database.connections.tenant.username' =>  $_ENV['TENANT_DB_USERNAME'],
        'database.connections.tenant.password' =>  $_ENV['TENANT_DB_PASSWORD'],
        'database.connections.tenant.port' =>  $_ENV['TENANT_DB_PORT'],

		'app.key' => $_ENV['TENANT_KEY']
    ]);


    DB::purge('tenant');

    DB::reconnect('tenant');

    Schema::connection('tenant')->getConnection()->reconnect();

    return $this;
}

Since i'm new to Laravel and don't know it's inner workings that well, i've read up on Laravel enviroment files en config. What i understand from the documentation is that the config is cahced for optimisation and must be cleared on deploy.

But what happens if i change the config app.key and other variables on the fly? Will this cause issues for the tenants? Data stored in wrong database or encrypted with wrong key?

Each tenant will also have a api that will be open to receive incoming data, lets say for example 1200+ people push data to 4 different tenants at the same moment. Can the caching break the app and corrupt the data per tenant?

Also is the approach of loading the data out of custom .env files a good solution or should i move to a database driven approach?

At this point i've spend days reading up and trying to come up with a solution but the dynamic programatically changing of the application config (esp. the app key) during high traffic is somewhat mindboggling.

Looking forward on reading your opinion and advice on this matter.

Best regards. Bart

0 likes
3 replies
jlrdw's avatar

Have you watched the multi-tenant video series right here on laracasts.

BMS51's avatar
Level 1

The only one i could find here on laracasts was multi tenancy in practice which makes use of a single database. Which in my case is not viable in my case because the data has to be stored in separated databases / separated database servers.

At this point my main concern is the changing the config() on production environment. if it's guaranteed not to be influenced by caching mechanismes.

AlexDC's avatar

The best solution is that you override the database class manager from your package. In my case, I'm using the Spatie multitenancy and I did it by creating a new class (using the provider's original class as a template)... then, in the config/multitenancy section, you do like this:

'switch_tenant_tasks' => [
    \Spatie\Multitenancy\Tasks\PrefixCacheTask::class,
    \Spatie\Multitenancy\Tasks\SwitchRouteCacheTask::class,
    // WE COMMENT the original spatie database switcher, so we'll use our own below...
    // \Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask::class,

    // Custom TASKS
    \App\Actions\Tipster\SetTenantConfig::class,
    \App\Actions\Tipster\TipsterSwitchTenantDatabase::class,
],

Please or to participate in this conversation.