Getting started
This page will go over installing the package and building a simple multi-domain multi-database demo, where each tenant has different users.
It’s recommended to follow this page in a fresh Laravel 11 application first, so that it’s easier for you to follow and make sense of the steps described here. After that, you should be able to confidently implement the package into an existing application.
Installing the package
To install the package, require it using composer:
Then, run the tenancy:install
command:
That will create the following files:
Directoryapp
DirectoryProviders
- TenancyServiceProvider.php event listeners and route registration
Directoryconfig
- tenancy.php where the package behavior is configured
Directorydatabase
Directorymigrations
- 2019_09_15_000010_create_tenants_table.php
- 2019_09_15_000020_create_domains_table.php
Directoryroutes
- tenant.php
The three highlighted files (of the five total) are required. The others can sometimes be removed. We’ll cover that later.
After these files are created, add TenancyServiceProvider
to your bootstrap/providers.php
array, directly below AppServiceProvider
:
With this, the package is installed. However, to demonstrate usage, we should do a few more things.
You can feel free to revert or change these, but I recommend following this guide in full to get a working multi-tenant app before you start customizing things.
The setup we’ll be using here is multi-domain multi-tenant. It’s what works best for the vast majority of applications, and is also the simplest, so it works great for our purposes here.
Setting up routing
Without any changes, Laravel is registering your web.php
routes in bootstrap/app.php
, and your tenant.php
routes are being registered in your TenancyServiceProvider
. However, there’s an edge case: which route should be used on a path defined in both web.php
and tenant.php
— such as /
?
To solve this, we need to scope the routes to their domains. tenant.php
is already doing this using the PreventAccessFromUnwantedDomains
middleware which prevents access from any domains defined in the tenancy.identification.central_domains
config. But we also need to scope the routes in web.php
.
There are two ways to do this. The first is to wrap your web.php
routes in a loop like this:
The other approach is a bit more complicated but will result in simpler route files. See Routing for more details.
Running migrations
The tenancy:install
command we ran earlier created two migrations. Let’s run them:
Now that we have the tenants
and domains
tables created, let’s configure our Tenant model.
Creating a Tenant model
Create a new model:
And configure it as the tenant model the package should use:
Adding a tenant migration
Let’s copy the create_users_table
migration to the database/migrations/tenant
folder, which got created automatically when you ran php artisan tenancy:install
:
In a fresh Laravel 11 application, your database/migrations
should now look like this:
Directorydatabase/migrations
- 0001_01_01_000000_create_users_table.php
- 0001_01_01_000001_create_cache_table.php
- 0001_01_01_000002_create_jobs_table.php
- 2019_09_15_000010_create_tenants_table.php
- 2019_09_15_000020_create_domains_table.php
Directorytenant
- 0001_01_01_000000_create_users_table.php
Now that we’ve moved the migration to the database/migrations/tenant
folder, the tables defined in that migration will get created whenever a tenant is created.
Creating a sample tenant
Now that our Tenant model is created and configured, let’s go ahead and use it to create an actual tenant:
Now that we’ve created our tenant along with its domain, we can open it in the browser:
example.test
should serve your/
route fromweb.php
(the Laravel welcome page by default)tenant1.example.test
should show:This is your multi-tenant application. The id of the current tenant is ...
The output demonstrates that the tenant was identified using the domain, but let’s also verify that the tenant is using their own database:
If you visit tenant1.example.test
again, you should see tenant
followed by a UUID.
Now let’s try to add some data to the tenant database:
Let’s change the route files:
Now you should see:
foo@example.test
ontenant1.example.test
bar@example.test
ontenant2.example.test
baz@example.test
onexample.test
(central domain)
And with that, you have a fully working multi-domain multi-database application!
To learn how to configure the package for your exact needs, make sure to read these pages next: