Make your Laravel application multi-tenant without changing a line of code

Published in Programming on Oct 6, 2019

How the stancl/tenancy package can make your Laravel application automatically multi-tenant, without any code changes.

Note: This article is outdated - it uses an old version of my multi-tenancy package. I recommend reading the updated version on Tenancy for Laravel docs

A package of mine, stancl/tenancy, lets you add multi-tenancy to Laravel applications without having to change how you write your app.

It automatically switches the database connection, cache, filesystem, Redis and queue in the background, letting you write code that doesn't need to be aware of any specifics related to multi-tenancy.

You can read more about the package here:


To install the package, first you need to require it via composer:

composer require stancl/tenancy

Then, you can use the install command to publish all assets and make the necessary changes to your http kernel.

php artisan tenancy:install

If you're not running this in a fresh Laravel application, it's wise to see what the install command does. It could cause issues if your application structure is too custom. Installing the package manually shouldn't take more than a minute.


For this package, routes are what distinguishes the tenant part of the application from the central part. Rather than applying model traits and similar things, just decide what routes belong to the tenant part of the app.

Routes for your tenant part of the application must be located in routes/tenant.php.

The routes/web.php file should be used for "central" routes — landing page, sign up page, etc.

Note that routes in these two files can't be conflicting, so it may be useful to prefix all tenant routes with app/, for example.


By default, when the application is visited, the package attempts to find a tenant who owns the domain in the request.

If the current domain doesn't belong to any tenant, an exception is thrown.

Add the domains for the central part of the application to the tenancy.exempt_domains config:

// config/tenancy.php
'exempt_domains' => [

Tenant migrations

Move the migrations that should interact with tenant databases to migrations/tenant.

Creating tenants

Finally, creating tenants. The last step to have a working multi-tenant app.

To create a tenant, you may use the following method:

use Stancl\Tenancy\Tenant;


To test your application locally, you may use domains under the .localhost top level domain. All of those domains are routed to

Testing it out

Let's create two tenants: one on the foo.localhost domain and one on the bar.localhost domain.

You can run these methods in php artisan tinker for development.

use Stancl\Tenancy\Tenant;

$tenant1 = Tenant::new()->withDomains('foo.localhost')->save();
$tenant2 = Tenant::new()->withDomains('bar.localhost')->save();

Make sure your application is running on localhost and your web server accepts all hostnames (artisan serve does).

Now, you can visit your multi-tenant application on foo.localhost and bar.localhost, with both tenants having their own database, cache, queues, filesystem, and Redis.

It's likely you'll get a Table not found error when you visit the page — if it interacts with the database. To run tenant migrations, use the following artisan command:

php artisan tenants:migrate


And that's all there is to implementing multi-tenancy with stancl/tenancy.

Of course, in real world applications you need more things:

  • storing additional information about the tenants, such as their subscription plan
  • setting application config to tenant-specific values
  • integrating with other packages, like Horizon and Telescope
  • using custom database connections for specific tenants, to allow for on-premise database hosting
  • testing your multi-tenant application

All of this, and much more, is covered in the package's documentation.

Thank you for reading this and I wish you success with your Software-as-a-Service.


You will be notified whenever I publish an article about the topics you selected. Unsubscribe anytime.


Your comment will appear once it's approved (to fight spam).