Kritim Yantra
May 06, 2025
If you’re building a SaaS (Software as a Service) product with Laravel, where each customer has isolated data (like a CRM, School Management System, or Project Tool), you’ve likely come across the term multi-tenancy.
Multi-tenancy means one Laravel application serves multiple tenants (clients). Each tenant can have its own users, data, and even design.
In this guide, we'll learn how to implement multi-tenancy using the Tenancy for Laravel package, created by Stancl.
Imagine you're building an app like Notion or Slack. Each company (tenant) should:
This is where multi-tenancy comes in. You don't create a new Laravel project for each customer — you use one app and separate the data per tenant.
Tenancy for Laravel supports two types:
All tenants share one database but their records are separated using a tenant_id
.
✔️ Easy to set up
❌ Data not physically isolated
Each tenant has a separate database.
✔️ Full data isolation
✔️ Better for large clients
❌ Slightly complex setup
We’ll focus on multi-database as it’s the most powerful and scalable.
Let’s start from scratch.
composer create-project laravel/laravel multi-tenancy-app
cd multi-tenancy-app
composer require stancl/tenancy
Now publish the config file:
php artisan tenancy:install
This creates:
config/tenancy.php
Run migrations:
php artisan migrate
Tenancy uses a Tenant
model (stored in the central database) to store tenant metadata like domains.
You already have a tenants
table created after install.
You can create a tenant like this:
use Stancl\Tenancy\Database\Models\Tenant;
$tenant = Tenant::create([
'id' => 'acme', // Unique ID
]);
$tenant->domains()->create([
'domain' => 'acme.localhost', // Map domain
]);
🎯 Tip: Use
.localhost
for testing subdomains locally.
To test subdomains locally, edit your hosts
file:
127.0.0.1 acme.localhost
127.0.0.1 globex.localhost
Start Laravel server:
php artisan serve --host=localhost --port=8000
To isolate tenant data, you need tenant-specific tables (e.g., users
, projects
, etc.).
Create a migration using:
php artisan tenancy:make:migration create_users_table
It will be saved in database/migrations/tenant/
.
Example:
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
Now run it for all tenants:
php artisan tenants:migrate
Tenancy will automatically detect the tenant based on the subdomain or domain.
You can configure this in config/tenancy.php
:
'identification_middleware' => [
\Stancl\Tenancy\Middleware\InitializeTenancyByDomain::class,
],
You can also use InitializeTenancyBySubdomain
.
By default, routes inside routes/tenant.php
are only accessible under tenant domains.
// routes/tenant.php
Route::get('/', function () {
return 'Tenant Home: ' . tenant('id');
});
Visit:
http://acme.localhost
It will show: Tenant Home: acme
To create seeders for tenants:
php artisan make:seeder TenantUserSeeder
Run for a specific tenant:
$tenant->run(function () {
\App\Models\User::factory()->count(10)->create();
});
If you're running artisan commands or jobs, you may want to switch tenants manually:
use Stancl\Tenancy\Tenant;
$tenant = Tenant::find('acme');
$tenant->run(function () {
// Code runs in tenant DB
\App\Models\User::create(['name' => 'Test']);
});
Tenancy fires many events during tenant lifecycle.
Example: Seed user after tenant creation
Event::listen(TenantCreated::class, function ($event) {
$event->tenant->run(function () {
User::create([
'name' => 'Admin',
'email' => 'admin@demo.com',
]);
});
});
Sometimes you want shared models like Plan
, Subscription
, etc.
Use UsesTenantConnection
trait for tenant models, and avoid it for central ones.
// Tenant Model
use Stancl\Tenancy\Database\Concerns\UsesTenantConnection;
// Central Model (normal Eloquent model)
class Plan extends Model {
// uses central database
}
Main App (central) — auth, pricing, subscription
When a user signs up:
Redirect to subdomain login
Each tenant has its own DB with user, projects, etc.
Tenancy for Laravel makes building multi-tenant SaaS platforms a breeze. It’s flexible, event-driven, and supports both single and multi-database setups.
You now have the tools to build:
Drop your questions or share your SaaS idea in the comments — happy to help!
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google