magetech / laravel-saas-tenancy
Multi-tenant architecture for Laravel SaaS applications — shared database or database-per-tenant with zero code changes to switch strategies.
dev-main
2026-08-25 13:18 UTC
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^2.0|^3.0
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- pestphp/pest: ^2.0|^3.0
- phpunit/phpunit: ^10.0|^11.0|^12.0
This package is not auto-updated.
Last update: 2026-08-25 19:46:58 UTC
README
Multi-tenant SaaS infrastructure for Laravel with tenant isolation, user management, and middleware support.
Features
- Multi-tenant Architecture — Shared database or database-per-tenant strategies
- Tenant Identification — Subdomain, path, header, session, or cookie resolvers
- User Management — Tenant-scoped users with roles (owner, admin, member, viewer)
- Middleware Stack — IdentifyTenant, InitializeTenancy, PreventTenantMixing
- Query Scoping — Auto-scope Eloquent queries by tenant
- Activity Logging — Track tenant events (created, activated, suspended, deleted)
- Package Tool — CLI commands for tenant management
Requirements
- PHP 8.3+
- Laravel 11.x, 12.x, or 13.x
magepackages/package-toolkit(auto-installed)
Installation
composer require magepackages/laravel-saas-tenancy php artisan mts:saas:install
Quick Start
1. Run Migrations
php artisan migrate
2. Create a Tenant
php artisan mts:saas:create-tenant "Acme Corp"
3. Identify Tenants
use MageTech\SaaS\Support\Facades\Tenant; // Identify current tenant Tenant::identify(); // Get current tenant $tenant = Tenant::getTenant(); // Create a tenant $tenant = Tenant::create(['name' => 'Acme', 'slug' => 'acme']);
4. Use Models
use MageTech\SaaS\Models\Tenant; use MageTech\SaaS\Models\TenantUser; // Get tenant users $users = TenantUser::forTenant($tenant->id)->get(); // Check role if ($tenantUser->isAdmin()) { // ... }
5. Scoping Queries
use MageTech\SaaS\Concerns\BelongsToTenant; class Order extends Model { use BelongsToTenant; } // Auto-scoped to current tenant $orders = Order::all(); // Without scope $allOrders = Order::withoutGlobalScope(TenantScope::class)->get();
Configuration
Config is published to config/mts-saas.php:
return [ 'strategy' => 'shared', // 'shared' or 'database' 'key_type' => 'uuid', // 'uuid', 'ulid', or 'int' 'resolvers' => [ 'subdomain' => ['enabled' => true], 'path' => ['enabled' => false], // ... ], ];
Resolvers
| Resolver | Description |
|---|---|
| Subdomain | Extracts tenant from acme.example.com |
| Domain | Maps domain to tenant |
| Path | Extracts tenant from URL /acme/... |
| Header | Reads X-Tenant-ID header |
| Session | Reads tenant from session |
| Cookie | Reads tenant from cookie |
Events
TenantCreated— Fired when a tenant is createdTenantActivated— Fired when a tenant is activatedTenantSuspended— Fired when a tenant is suspendedTenantDeleted— Fired when a tenant is deletedTenantIdentified— Fired when a tenant is identifiedTenantDatabaseReady— Fired when tenant database is ready
License
MIT License