Multi-Tenant SaaS Applications with Laravel
Abdullah Shakir
Full-Stack Developer | Software Engineer | VueJS | Laravel | PHP | 7+ years | Grew a startup from scratch to 1M users in <3 years
Multi-tenant SaaS (Software as a Service) applications are designed to serve multiple customers, or tenants, from a single codebase. Each tenant has its own isolated data and configuration, while sharing the underlying infrastructure. Building a multi-tenant SaaS application with Laravel can be an efficient way to deliver scalable solutions to a diverse client base. Here’s a practical guide on how to approach this with Laravel.
Understanding Multi-Tenancy
In a multi-tenant application, tenants are distinct entities with their own data and configurations. There are several approaches to multi-tenancy:
Laravel's flexibility allows you to implement any of these approaches. For simplicity, we'll focus on the Single Database, Shared Schema approach, which is commonly used due to its balance of simplicity and efficiency.
Setting Up Laravel for Multi-Tenancy
Database structure
Define a tenant_id column in tables that need to be tenant-specific. This column helps to distinguish data belonging to different tenants.
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id'); // Tenant ID
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
// Index to speed up queries by tenant
$table->index('tenant_id');
});
Middle ware for tenant identification
Create middleware to identify and set the tenant for each request. This is crucial for ensuring that tenant-specific data is correctly scoped.
// app/Http/Middleware/SetTenant.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\DB;
class SetTenant
{
public function handle($request, Closure $next)
{
$tenantId = $request->header('X-Tenant-ID'); // Extract tenant ID from request
// Set tenant-specific database connection if necessary
// DB::purge('mysql');
// config(['database.connections.mysql.database' => 'tenant_' . $tenantId]);
// Optionally: set tenant-specific configuration
// config(['app.tenant_id' => $tenantId]);
return $next($request);
}
}
Register this middleware in app/Http/Kernel.php:
protected $routeMiddleware = [
// Other middleware
'tenant' => \App\Http\Middleware\SetTenant::class,
];
领英推荐
Tenant Scoping in models
Modify your models to automatically filter data based on the current tenant:
// app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected static function booted()
{
static::addGlobalScope('tenant', function (Builder $builder) {
$tenantId = app('request')->header('X-Tenant-ID');
$builder->where('tenant_id', $tenantId);
});
}
}
Tenant Management
Implement tenant management features such as creation, modification, and deletion of tenants. Store tenant details in a separate table.
// Migration for tenants table
Schema::create('tenants', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('domain'); // Optional, for domain-based multi-tenancy
$table->timestamps();
});
Use Laravel’s Eloquent models and controllers to manage tenant data.
Handling Tenant Specific Configuration
If your tenants have unique configurations, you can manage these by storing tenant-specific settings in the database and loading them as needed.
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$tenantId = app('request')->header('X-Tenant-ID');
$tenant = \App\Models\Tenant::find($tenantId);
// Set tenant-specific configurations
config(['app.name' => $tenant->name]);
}
}
Testing and validation
Thoroughly test your multi-tenant implementation to ensure data isolation and integrity. Use Laravel’s testing tools to create comprehensive test cases that simulate tenant interactions.
// Example test for tenant-specific data access
public function testTenantDataIsolation()
{
$tenantId = 1;
$response = $this->withHeaders(['X-Tenant-ID' => $tenantId])->get('/api/users');
$response->assertStatus(200);
$this->assertDatabaseHas('users', ['tenant_id' => $tenantId]);
}
Conclusion
Building a multi-tenant SaaS application with Laravel involves careful planning and implementation to ensure tenant data isolation and efficient performance. By setting up proper database structures, middleware, and tenant management features, you can create a scalable and maintainable solution that serves multiple clients from a single application. Laravel's flexibility and robust features make it a powerful choice for developing multi-tenant SaaS applications, enabling you to build sophisticated solutions with ease.
#Laravel #SaaS #MultiTenant #WebDevelopment