PHPackages                             rylxes/laravel-multitenancy - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. rylxes/laravel-multitenancy

ActiveLibrary

rylxes/laravel-multitenancy
===========================

Simple by default, powerful when needed. Single-database and multi-database multitenancy for Laravel.

v1.0.0(2mo ago)00MITPHPPHP ^8.1CI failing

Since Mar 8Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/rylxes/laravel-multitenancy)[ Packagist](https://packagist.org/packages/rylxes/laravel-multitenancy)[ Docs](https://github.com/rylxes/laravel-multitenancy)[ RSS](/packages/rylxes-laravel-multitenancy/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (7)Versions (2)Used By (0)

Laravel Multitenancy
====================

[](#laravel-multitenancy)

> **[Full Documentation](https://rylxes.com/docs/laravel-multitenancy)** — Complete usage guide, configuration reference, and API docs.

[![Latest Version on Packagist](https://camo.githubusercontent.com/4ede5613ce286e19967bc86943132487d2634b18a949248f406e96c5e10135a8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f72796c7865732f6c61726176656c2d6d756c746974656e616e63792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rylxes/laravel-multitenancy)[![Total Downloads](https://camo.githubusercontent.com/e9074279b249d484dc0b37e33b419f825bf2aba5f1464d1d8c6c3ee457d7084e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f72796c7865732f6c61726176656c2d6d756c746974656e616e63792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rylxes/laravel-multitenancy)[![License](https://camo.githubusercontent.com/f4710fe0cf241f5a345f5bd6251ffaad988c59904d9ac38ffd8bf9b2ad27a210/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f72796c7865732f6c61726176656c2d6d756c746974656e616e63792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rylxes/laravel-multitenancy)[![PHP Version](https://camo.githubusercontent.com/5735540f0c8454a2f86f081524d80c75a8c8fa6c096ccc0d19a503732900c0b4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f72796c7865732f6c61726176656c2d6d756c746974656e616e63792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rylxes/laravel-multitenancy)

Simple, safe multi-tenancy for Laravel. Single-database by default, multi-database when you need it.

Why This Package?
-----------------

[](#why-this-package)

Pain PointSolutionData leakage between tenants`BelongsToTenant` trait + safeguard mode throws on unscoped queriesCache pollution`PrefixCacheTask` auto-prefixes cache keys per tenantStorage file mixing`PrefixFilesystemTask` isolates disk paths per tenantQueue jobs losing contextFirst-class integration with [laravel-tenant-jobs](https://github.com/rylxes/laravel-tenant-jobs)No fail-safe for missing scopesSafeguard throws `NoCurrentTenantException` on unscoped queriesMigration complexity`tenant:migrate` runs migrations across all tenantsTesting difficulty`ActingAsTenant` trait for clean test setupNo CLI tenant management6 artisan commands out of the boxRequirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10, 11, or 12

Installation
------------

[](#installation)

```
composer require rylxes/laravel-multitenancy
```

Publish config and run migrations:

```
php artisan vendor:publish --tag=multitenancy-config
php artisan migrate
```

Quick Start (5 Minutes)
-----------------------

[](#quick-start-5-minutes)

### 1. Create a tenant

[](#1-create-a-tenant)

```
php artisan tenant:create "Acme Corp" --domain=acme.example.com
```

### 2. Add `tenant_id` to your models' tables

[](#2-add-tenant_id-to-your-models-tables)

```
Schema::table('projects', function (Blueprint $table) {
    $table->foreignId('tenant_id')->constrained()->index();
});
```

### 3. Use the `BelongsToTenant` trait

[](#3-use-the-belongstotenant-trait)

```
use Illuminate\Database\Eloquent\Model;
use Rylxes\Multitenancy\Concerns\BelongsToTenant;

class Project extends Model
{
    use BelongsToTenant;
}
```

That's it. All queries on `Project` are now automatically scoped to the current tenant, and `tenant_id` is auto-filled on creation.

### 4. Add middleware to your routes

[](#4-add-middleware-to-your-routes)

```
// routes/web.php or bootstrap/app.php
Route::middleware('tenancy')->group(function () {
    Route::resource('projects', ProjectController::class);
});
```

Tenant Identification
---------------------

[](#tenant-identification)

The package resolves tenants from incoming requests. Choose a strategy in `config/multitenancy.php`:

```
'tenant_finder' => \Rylxes\Multitenancy\Finders\DomainTenantFinder::class,
```

FinderHow it worksBest for`DomainTenantFinder`Matches `request->getHost()`Custom domains (`acme.com`)`SubdomainTenantFinder`Extracts first subdomain partSaaS subdomains (`acme.app.com`)`PathTenantFinder`Uses first URL segmentPath-based (`app.com/acme/...`)`HeaderTenantFinder`Reads `X-Tenant-ID` headerAPIs and SPAsData Isolation
--------------

[](#data-isolation)

### BelongsToTenant Trait

[](#belongstotenant-trait)

Add to any Eloquent model to auto-scope all queries and auto-fill `tenant_id`:

```
use Rylxes\Multitenancy\Concerns\BelongsToTenant;

class Invoice extends Model
{
    use BelongsToTenant;
}

// Automatically adds WHERE tenant_id = ? to all queries
$invoices = Invoice::all(); // Only current tenant's invoices

// tenant_id auto-filled on create
$invoice = Invoice::create(['amount' => 100]); // tenant_id set automatically
```

### Safeguard Mode

[](#safeguard-mode)

When `safeguard` is `true` (default), the package throws `NoCurrentTenantException` if you query a tenant-scoped model without an active tenant. This prevents accidental data leakage:

```
// Without any tenant context active:
Invoice::all(); // Throws NoCurrentTenantException
```

### Admin/Landlord Queries

[](#adminlandlord-queries)

Bypass tenant scoping when needed:

```
// Get all invoices across all tenants (admin use)
$allInvoices = Invoice::withoutTenantScope()->get();
```

Cache &amp; Storage Isolation
-----------------------------

[](#cache--storage-isolation)

Enabled by default via switch tasks:

```
// config/multitenancy.php
'switch_tenant_tasks' => [
    PrefixCacheTask::class,        // Cache keys: tenant_1_key
    PrefixFilesystemTask::class,   // Storage: storage/app/tenant_1/
    ClearResolvedInstancesTask::class,
    // SwitchDatabaseTask::class,  // Uncomment for multi-database
],
```

Multi-Database Support
----------------------

[](#multi-database-support)

Uncomment `SwitchDatabaseTask` in config and set your tenant's `database` field:

```
php artisan tenant:create "Acme Corp" --domain=acme.example.com --database=tenant_acme
```

```
// config/multitenancy.php
'database' => [
    'strategy' => 'multi',
    'tenant_connection' => 'tenant',
    'landlord_connection' => env('DB_CONNECTION', 'mysql'),
],
```

Programmatic Usage
------------------

[](#programmatic-usage)

```
use Rylxes\Multitenancy\Facades\Tenant;

// Set current tenant
$tenant = \Rylxes\Multitenancy\Models\Tenant::find(1);
Tenant::makeCurrent($tenant);

// Check current tenant
Tenant::current();   // Returns Tenant model or null
Tenant::check();     // Returns bool

// Run code as a specific tenant
Tenant::execute($tenant, function () {
    // All queries scoped to $tenant here
    $projects = Project::all();
});
// Previous tenant context (or none) is restored after

// Global helper
tenant();            // Returns current Tenant or null

// Forget current tenant
Tenant::forgetCurrent();
```

Artisan Commands
----------------

[](#artisan-commands)

CommandDescription`tenant:list`List all tenants`tenant:create {name}`Create a tenant (`--domain=`, `--database=`)`tenant:delete {id}`Delete a tenant (with confirmation)`tenant:migrate`Run migrations for all tenants (`--tenant=` for one)`tenant:seed`Seed databases for all tenants`tenant:artisan {command}`Run any artisan command for all tenantsEvents
------

[](#events)

EventWhen`TenantMadeCurrent`After a tenant is set as current`TenantForgotten`After tenant context is cleared`TenantCreated`After a new tenant is created`TenantDeleted`After a tenant is deletedQueue Jobs
----------

[](#queue-jobs)

For tenant-aware queue jobs, install [laravel-tenant-jobs](https://github.com/rylxes/laravel-tenant-jobs):

```
composer require rylxes/laravel-tenant-jobs
```

Zero-config integration — `laravel-tenant-jobs` auto-detects this package and handles tenant context in all queued jobs, batch callbacks, retries, scheduled tasks, and notifications.

Testing
-------

[](#testing)

Use the `ActingAsTenant` trait in your tests:

```
use Rylxes\Multitenancy\Testing\ActingAsTenant;

class ProjectTest extends TestCase
{
    use ActingAsTenant;

    public function test_projects_are_scoped_to_tenant(): void
    {
        $tenant = Tenant::create(['name' => 'Test']);
        $this->actingAsTenant($tenant);

        $project = Project::create(['name' => 'My Project']);

        $this->assertEquals($tenant->id, $project->tenant_id);
    }
}
```

Configuration Reference
-----------------------

[](#configuration-reference)

```
// config/multitenancy.php
return [
    'tenant_model'   => \Rylxes\Multitenancy\Models\Tenant::class,
    'tenant_finder'  => \Rylxes\Multitenancy\Finders\DomainTenantFinder::class,
    'tenant_column'  => 'tenant_id',
    'safeguard'      => true,  // Throw on unscoped tenant queries

    'switch_tenant_tasks' => [
        PrefixCacheTask::class,
        PrefixFilesystemTask::class,
        ClearResolvedInstancesTask::class,
        // SwitchDatabaseTask::class, // Uncomment for multi-DB
    ],

    'database' => [
        'strategy' => 'single', // 'single' or 'multi'
        'tenant_connection' => 'tenant',
        'landlord_connection' => env('DB_CONNECTION', 'mysql'),
    ],

    'cache' => ['prefix_base' => 'tenant_'],
    'filesystem' => [
        'suffix_base' => 'tenant_',
        'disks' => ['local', 'public'],
    ],
];
```

Architecture
------------

[](#architecture)

```
src/
  TenantManager.php              — Core singleton: makeCurrent/forgetCurrent/execute
  MultitenancyServiceProvider.php — Config, migrations, commands, middleware
  Models/Tenant.php              — Eloquent model
  Facades/Tenant.php             — Facade for TenantManager
  Contracts/TenantFinder.php     — Interface for identification strategies
  Finders/                       — Domain, Subdomain, Path, Header finders
  Concerns/
    BelongsToTenant.php          — Trait: global scope + auto-fill tenant_id
    TenantAware.php              — Trait: iterate commands over tenants
  Scopes/TenantScope.php         — Global scope: WHERE tenant_id = ?
  Tasks/                         — Cache, Filesystem, Database, Instance switching
  Middleware/                    — InitializeTenancy, EnsureTenantSession
  Events/                       — TenantMadeCurrent, Forgotten, Created, Deleted
  Console/Commands/              — 6 tenant management commands
  Testing/ActingAsTenant.php     — Test helper trait

```

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

37

—

LowBetter than 82% of packages

Maintenance94

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

62d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8102778abfe9dfee27e418fd9f73a66272ac9ed13df456b5186c5b88676f7ce6?d=identicon)[rylxes](/maintainers/rylxes)

---

Top Contributors

[![rylxes](https://avatars.githubusercontent.com/u/1958058?v=4)](https://github.com/rylxes "rylxes (2 commits)")

---

Tags

laravelsaastenantmulti-tenantmultitenancysingle database

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/rylxes-laravel-multitenancy/health.svg)

```
[![Health](https://phpackages.com/badges/rylxes-laravel-multitenancy/health.svg)](https://phpackages.com/packages/rylxes-laravel-multitenancy)
```

###  Alternatives

[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k43.5M5.2k](/packages/larastan-larastan)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[yadahan/laravel-authentication-log

Laravel Authentication Log provides authentication logger and notification for Laravel.

416632.8k5](/packages/yadahan-laravel-authentication-log)[toponepercent/baum

Baum is an implementation of the Nested Set pattern for Eloquent models.

3154.7k](/packages/toponepercent-baum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
