A powerful and flexible single-database multi-tenant solution for Laravel 12+, built with SOLID principles in mind.
- Early Identification: Initialize tenants during application boot for maximum performance
- Flexible Resolution: Support for domain and subdomain-based tenant resolution
- Customizable Bootstrapping: Add your own tenant bootstrapping logic
- Tenant-Aware Systems:
- Queue system with automatic tenant context
- Cache system with tenant-specific prefixes
- Session management with tenant isolation
- Built-in Spatie Permissions Support: Automatic tenant-specific permission caching
- Automatic Tenant Scoping: Zero-effort tenant data isolation with the
BelongsToTenanttrait - High Performance: Optimized resolver with optional caching
- Developer Friendly: Clear API with helper functions
- PHP 8.3 or higher
- Laravel 12.x or higher
- Install the package via Composer:
composer require revoltify/tenantify- Run the installation command:
php artisan tenantify:installThis will publish the configuration file and migrations.
- Run the migrations:
php artisan migrateThe package can be configured via the config/tenantify.php file. Here are the key configuration options:
'early' => env('TENANTIFY_EARLY', false),true: Initializes tenant during application boot (recommended for fully tenant-aware applications)false: Manual initialization through middleware (recommended for partially tenant-aware applications)
'models' => [
'tenant' => \App\Models\Tenant::class,
'domain' => \App\Models\Domain::class,
],'resolver' => [
'class' => \Revoltify\Tenantify\Resolvers\DomainResolver::class,
'cache' => [
'enabled' => env('TENANTIFY_CACHE_ENABLED', false),
'ttl' => env('TENANTIFY_CACHE_TTL', 3600),
],
],use Revoltify\Tenantify\Models\Tenant;
use Revoltify\Tenantify\Models\Domain;
$tenant = Tenant::create([
'name' => 'Example Organization'
]);
$tenant->domains()->create([
'domain' => 'example.com'
]);// Using facade
Tenantify::initialize($tenant);
// Using helper function
tenantify()->initialize($tenant);
// Initialize by ID
tenantify()->initialize($tenantId);// Using helper functions
$tenant = tenant();
$tenantId = tenant_id();
// Using facade
$tenant = Tenantify::tenant();Create a custom bootstrapper by extending the AbstractBootstrapper class:
use Revoltify\Tenantify\Bootstrappers\AbstractBootstrapper;
use Revoltify\Tenantify\Models\Contracts\TenantInterface;
class CustomBootstrapper extends AbstractBootstrapper
{
protected int $priority = 10;
public function bootstrap(TenantInterface $tenant): void
{
// Your bootstrapping logic here
}
public function revert(): void
{
// Your cleanup logic here
}
}Register your bootstrapper in the configuration:
'bootstrappers' => [
\App\Bootstrappers\CustomBootstrapper::class,
],Add automatic tenant scoping to your models using the BelongsToTenant trait:
use Illuminate\Database\Eloquent\Model;
use Revoltify\Tenantify\Models\Concerns\BelongsToTenant;
class Project extends Model
{
use BelongsToTenant;
protected $fillable = ['name', 'description'];
}This will automatically:
- Add tenant ID on model creation
- Scope all queries to the current tenant
- Establish the tenant relationship
Usage example:
// Creates a project for the current tenant automatically
$project = Project::create([
'name' => 'New Project'
]);
// Queries are automatically scoped to the current tenant
$projects = Project::all(); // Only returns current tenant's projects
// Access the tenant relationship
$tenant = $project->tenant;Make your job tenant-aware by implementing the TenantAware interface:
use Illuminate\Contracts\Queue\ShouldQueue;
use Revoltify\Tenantify\Job\TenantAware;
class ProcessTenantData implements ShouldQueue, TenantAware
{
public function handle(): void
{
// Job will automatically run in the correct tenant context
}
}Please see CONTRIBUTING.md for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.