Laravel is a popular PHP web application framework that is widely used to build scalable and maintainable web applications. However, when it comes to building multi-tenant applications, Laravel can become a bit challenging. This is where Laravel Tenancy comes into play. In this article, we will introduce you to Tenancy for Laravel, what it is, and why you should use it.
What is Tenancy for Laravel?
Tenancy for Laravel is a package that allows you to create multi-tenant Laravel applications. With Tenancy, you can create a single Laravel application that can serve multiple tenants, each with its own database schema, data, and configuration. Tenancy achieves this by intercepting the incoming HTTP requests and dynamically switching the database connection and other configurations based on the tenant.
As an example, You have a multi-tenancy LMS application at aptreelms.com. When you or your user visits pram.aptreelms.com, you are actually using Aptree LMS owned by Pram, which that website has its own database and configuration, same scenario is applied to fachtur.aptreelms.com. Both websites use the same single codebase, therefore it's called multi-tenancy.
Why Use Tenancy for Laravel?
Simplified Development
With Tenancy, you can create a single codebase for your multi-tenant Laravel application. This means that you can reuse the same code for all tenants, and only the configurations and data will be different. This makes the development process simpler and more efficient.
Reduced Costs
Creating separate Laravel applications for each tenant can be costly and time-consuming. With Tenancy, you can reduce the costs and time spent on development by creating a single codebase and reusing the same code for all tenants.
Easy Management
Tenancy allows you to manage all your tenants from a single dashboard. You can easily create, update, and delete tenants, and manage their configurations and data.
Increased Efficiency
Multi-tenancy can increase efficiency by reducing development and maintenance efforts, and by providing a single application instance for multiple tenants. This reduces duplication of effort, leading to faster development and reduced time-to-market.
Example Usage
To use Tenancy for Laravel, you first need to install it using Composer. You can do this by running the following command in your terminal:
composer require tenancy/tenancy
Then, run the tenancy:install
command:
php artisan tenancy:install
This will create a few files: migrations, config file, route file and a service provider.
Let's run the migrations:
php artisan migrate
Register the service provider in config/app.php
. Make sure it's on the same position as in the code snippet below:
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\TenancyServiceProvider::class, // <-- here
Create a Laravel Model for Tenant
<?php
namespace App\Models;
use Stancl\Tenancy\Database\Models\Tenant as BaseTenant;
use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Database\Concerns\HasDatabase;
use Stancl\Tenancy\Database\Concerns\HasDomains;
class Tenant extends BaseTenant implements TenantWithDatabase
{
use HasDatabase, HasDomains;
}
Separate the central web routes and tenant routes by making a small change to the app/Providers/RouteServiceProvider.php
file. Specifically, we'll make sure that central routes are registered on central domains only.
protected function mapWebRoutes()
{
foreach ($this->centralDomains() as $domain) {
Route::middleware('web')
->domain($domain)
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
}
protected function mapApiRoutes()
{
foreach ($this->centralDomains() as $domain) {
Route::prefix('api')
->domain($domain)
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
}
protected function centralDomains(): array
{
return config('tenancy.central_domains');
}
Call these methods manually from your RouteServiceProvider's boot()
method, instead of the $this->routes()
calls.
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
$this->mapApiRoutes();
$this->mapWebRoutes();
});
}
Specify the central domains. A central domain is a domain that serves your "central app" content, e.g. the landing page where tenants sign up. Open the config/tenancy.php
file and add them in:
A central domain is a domain that serves your "central app" content, e.g. the landing page where tenants sign up. Open the config/tenancy.php file and add them in:
'central_domains' => [
'saas.test', // Add the ones that you use. I use this one with Laravel Valet.
],
Now in your tenant.php
route file, it should look like this:
Route::middleware([
'web',
InitializeTenancyByDomain::class,
PreventAccessFromCentralDomains::class,
])->group(function () {
Route::get('/', function () {
return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id');
});
});
These routes will only be accessible on tenant (non-central) domains — the PreventAccessFromCentralDomains
middleware enforces that.
Now you can test if the tenant site is accessible or not by visiting your tenant site, inside your tenant.php
file add the following codes example:
Route::get('/', function () {
dd(\App\Models\User::all());
return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id');
});
Conclusion
Overall, multi-tenancy can provide significant benefits over single-tenancy, especially for software applications that need to serve multiple customers with varying needs and requirements. However, it's important to carefully evaluate the requirements of your application and the needs of your customers before deciding on a multi-tenancy approach.
Although multi-tenancy can provide mentioned benefits, this approach can also significantly increase the DevOps complexity.
For more reading about Tenancy for Laravel: https://tenancyforlaravel.com/