PHPackages                             glimmer/tenancy - 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. glimmer/tenancy

ActiveLibrary

glimmer/tenancy
===============

Opinionated and extended Spatie Multitenancy

1981PHPCI passing

Since Apr 13Pushed 1mo agoCompare

[ Source](https://github.com/glimmer-labs/tenancy)[ Packagist](https://packagist.org/packages/glimmer/tenancy)[ RSS](/packages/glimmer-tenancy/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (2)Used By (0)

Glimmer Tenancy
===============

[](#glimmer-tenancy)

#### An opinionated Spatie Multitenancy extension package for Laravel

[](#an-opinionated-spatie-multitenancy-extension-package-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/b6355ff3e9f421d5980939d30392f5430c2a25e55b53059d4ba994c1b8b7333e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f676c696d6d65722f74656e616e63793f7374796c653d666c61742d737175617265)](https://packagist.org/packages/glimmer/tenancy)[![GitHub Tests Action Status](https://camo.githubusercontent.com/534ed33726b21711e8fe53ef9f6294bb72d65be8b06635a547b59ac7c964439d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6c61726176656c2d676c696d6d65722f74656e616e63792f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d5465737473267374796c653d666c61742d737175617265)](https://github.com/laravel-glimmer/tenancy/actions/workflows/tests.yml?query=branch%3Amain)[![Laravel Octane Compatibility](https://camo.githubusercontent.com/70359a356da237cd29561bc5d0bb80baae775b5ff62f288ed324755382858342/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2532304f6374616e652d436f6d70617469626c652d737563636573733f7374796c653d666c6174266c6f676f3d6c61726176656c)](https://laravel.com/docs/12.x/octane#introduction)

This package extends [spatie/laravel-multitenancy](https://github.com/spatie/laravel-multitenancy) with additional opinionated features. For example, it defaults to multi-database tenancy but takes a different approach than Spatie's implementation.

Since this package builds upon Spatie’s, it retains most original concepts and functionality. It’s recommended to review Spatie's official documentation before using this package.

### What makes it opinionated?

[](#what-makes-it-opinionated)

- It uses a multi-database approach by default, creating a new connection for each tenant.
- Different landlord/tenant migrations structure.
- Auto-routing files with predefined middlewares.
- Additional tasks and tenant finders that expect the model to have certain columns.
- Allows queue jobs to run in both tenant and landlord contexts.

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

[](#installation)

```
composer require glimmer/tenancy
```

All files (routes, config, migrations) can be published at once by running:

```
php artisan vendor:publish --provider="Glimmer\Tenancy\TenancyServiceProvider"
```

Features
--------

[](#features)

#### Additional Tenant Switching Tasks:

[](#additional-tenant-switching-tasks)

- `PrefixFilesystemTask` – Prefixes filesystem disk paths with the tenant key (ID) using `league/flysystem-path-prefixing`.
- `PrefixScoutTask` – Prefixes Laravel Scout index names in `config/scout.php` with the tenant key.
- `PrefixSpatiePermissionTask` – Adds a tenant-specific prefix to Spatie Permission cache keys.

#### Enhanced Tenant Switching Tasks:

[](#enhanced-tenant-switching-tasks)

- `SwitchDatabaseConnectionTask` (Replaces Spatie’s `SwitchTenantDatabaseTask`) – Multi-database approach that creates a connection for each tenant using the landlord’s default connection (`.env` setting) and dynamically switches between them.
    - A different connection can be specified per tenant by setting the `database_connection` column in the tenant model.
    - Individual connection configurations can be overridden using the `connection_config` column.
    - The database name can be changed within the `connection_config` array by defining `'database' => 'name'`.
    - This approach improves performance by avoiding frequent reconnections but slightly increases memory usage, especially in Laravel Octane environments.

#### Tenant Finders

[](#tenant-finders)

- `DomainTenantFinder` – Finds the tenant by matching the request domain with the entries in the tenant model’s `hosts`array.
- `SubdomainTenantFinder` – Identifies the tenant using the subdomain from the request, based on the `hosts` array in the model.
- `PathTenantFinder` – Determines the tenant by extracting its ID from the request path.
- `DomainAndSubdomainTenantFinder` – Matches tenants using either the request’s domain or subdomain.

> The `hosts` array in the tenant model can contain a list of either domains or subdomains.

#### Queue Enhancements:

[](#queue-enhancements)

- `MakeQueueMaybeTenantAwareAction` – A modified `MakeQueueTenantAwareAction` allowing jobs to run in both tenant and landlord contexts if the job implements `MaybeTenantAware`.
- `MaybeTenantAware` – An interface that allows jobs to be dispatched with/without tenant context depending on the job implementation.
- `tenant events` - Allows executing certain jobs when a tenant event is fired. (Job must extend `TenantEventQueue`) (Jobs must be defined on `multitenancy.php` config file with its respective event)

#### Tenant events:

[](#tenant-events)

For these events to work, the `HasTenantEvents` trait must be used in the tenant model (which is already included in Glimmer's `Tenant` model).

- `CreateDatabase` – Triggered when a tenant is created.
- `MigrateDatabase` – Fired after tenant creation to apply migrations (expects migrations to be at: `database/migrations/tenant`).
- `SeedDatabase` – Runs database seeders upon tenant creation.
    - Defaults to `DatabaseSeeder.php` but will use `tenant/DatabaseSeeder.php` if it exists.

#### Seeder Utilities:

[](#seeder-utilities)

- `ChainSeeding` – A trait that allows chaining multiple seeders to be executed sequentially.
    - Can be used in any class that needs to dispatch multiple seeders in a specific order.
    - Supports both seeder class names and closures as seeders.
    - Example usage:

    ```
    use Glimmer\Tenancy\Traits\ChainSeeding;

    class MySeeder extends Seeder
    {
        use ChainSeeding;

        public function run()
        {
            // Chain multiple seeders
            $this->chain([
                FirstSeeder::class,
                SecondSeeder::class,
                function() {
                    // Custom seeding logic
                }
            ]);

            // Dispatch the chain of seeders
            $this->dispatchSeeders();
        }
    }
    ```

    - When using closures, make sure to register `SerializableClosure` as a maybe tenant aware job in your config:

    ```
    // config/multitenancy.php
    'maybe_tenant_aware_jobs' => [
        // ...
        \Laravel\SerializableClosure\SerializableClosure::class,
    ],
    ```

#### Command Enhancements:

[](#command-enhancements)

- `IsTenantAware`|`TenantAware` – A modification to `Spatie/Commands/Concerns/TenantAware` trait enabling SQLite usage without lock issues.
- `MaybeTenantAware` – A trait for commands that can be executed with/without tenant context.
- `tenants:artisan` – A modification that uses Glimmer's `IsTenantAware` trait to allow SQLite databases to be used without blocking commands.

#### Middlewares:

[](#middlewares)

- `EnsureNoTenantSession` - Prevents tenant session to be used on landlord routes.
- `ForbidsTenant` - Prevents tenant to access landlord routes.

### Extended functionality:

[](#extended-functionality)

- **Tenant Model** – `Glimmer/Tenancy/Models/Tenant` extends `Spatie\Multitenancy\Models\Tenant` with additional functionality as running events and determining the database name as expected.
- **Separated Route Files** – Landlord (landlord.php) and tenant (tenant.php) routes are managed separately, while `web.php` remains shared.
- **`IsSharedModel` trait** – Enables models to be shared between tenants and the landlord, ensuring synchronization across instances.
- **Automatic Route Registration** – Routes are automatically registered and assigned appropriate middlewares to prevent unauthorized access (this can be disabled in `multitenancy.php` config).
    - Tenant routes includes `NeedsTenant` and `EnsureValidTenantSession` middleware by default.
    - Landlord routes includes `ForbidsTenant` `EnsureNoTenantSession` middleware by default.
    - When using route auto-registration tenant routes names are prefixed with `tenant.` and landlord routes with `landlord.`.
    - If auto-registration is disabled, use `TenancyRoutes::landlord()` and/or `TenancyRoutes::tenant()` to register them by hand and group the routes you need.

    ```
      TenancyRoutes::landlord()->group(function () {
        Route::get('/dashboard', function () {
            return 'Landlord dashboard';
        })->name('dashboard');
      });

      TenancyRoutes::tenant()->group(function () {
          Route::get('/home', function () {
              return 'Tenant home';
          })->name('home');
      });
    ```

---

##### Notes:

[](#notes)

- To avoid showing `500` error on `NoCurrentTenant` or `TenantIsForbidden` exception and instead redirect to a route, you can add the following to your `bootstrap/app.php` in to the exception handler:

    ```
    use Glimmer\Tenancy\Facades\LandlordTenantException;

    return Application::configure(basePath: dirname(__DIR__))
        ....
        ->withExceptions(function (Exceptions $exceptions) {
            $exceptions->render(LandlordTenantException::redirect('your-route'));
        })->create();
    ```
- As disclosed before, major structural changes are migration paths for landlord and tenant, as landlord migrations are at `database/migrations` root and tenant migrations are at `database/migrations/tenant`, and so for migrating the landlord you need to run:

    ```
    php artisan migrate
    ```

    For migrating the tenant, you need to run:

    ```
    php artisan tenants:artisan "migrate --path=database/migrations/tenant"
    ```

    > Or instead, use Glimmer's tenant events, which will automatically migrate the tenant after creation.
- The `SwitchRouteCacheTask` should be considered hardly if needed. In many cases, middleware/controller checks can enforce route access restrictions without needing this task.

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance59

Moderate activity, may be stable

Popularity13

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity17

Early-stage or recently created project

 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/36aacd2b09c268a80381e6792dfa2bf0f217db0cafec77ee6b3c5ce32641c2db?d=identicon)[Haruki1707](/maintainers/Haruki1707)

---

Top Contributors

[![Haruki1707](https://avatars.githubusercontent.com/u/72423267?v=4)](https://github.com/Haruki1707 "Haruki1707 (64 commits)")

### Embed Badge

![Health badge](/badges/glimmer-tenancy/health.svg)

```
[![Health](https://phpackages.com/badges/glimmer-tenancy/health.svg)](https://phpackages.com/packages/glimmer-tenancy)
```

PHPackages © 2026

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