pg-tenancy / laravel-pg-tenancy
Laravel multi-tenancy for PostgreSQL schema isolation with connection pooling (subdomain, path, team modes)
Installs: 3
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/pg-tenancy/laravel-pg-tenancy
Requires
- php: >=8.2
- illuminate/config: ^10.0|^11.0|^12.0
- illuminate/console: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/events: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- mockery/mockery: ^1.5
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-01-11 17:48:40 UTC
README
Multi-tenancy for Laravel with PostgreSQL schema isolation and connection pooling. Supports subdomain, path, or Team model based tenancy modes.
Installation
- Require the package (adjust VCS path if local):
composer require pg-tennancy/laravel-pg-tenancy
- Publish config and migrations:
php artisan vendor:publish --provider="PgTenancy\\PgTenancyServiceProvider" --tag=tenancy-config php artisan vendor:publish --provider="PgTenancy\\PgTenancyServiceProvider" --tag=tenancy-migrations php artisan vendor:publish --provider="PgTenancy\\PgTenancyServiceProvider" --tag=tenancy-tenant-migrations
-
Configure
config/tenancy.phpand ensure a privilegedsystem_connectioncan create schemas/roles. -
Add middleware to HTTP kernel or route group:
// app/Http/Kernel.php protected $middlewareGroups = [ 'web' => [ // ... \PgTenancy\Http\Middleware\IdentifyTenant::class, ], ];
Modes
- Subdomain:
tenant1.example.com(configurebase_domain) - Path:
example.com/tenant1(configurepath_segment_index) - Team: authenticated user's team (configure relation name)
Schema Isolation
Each tenant gets its own PostgreSQL schema and role. The package sets the Postgres search_path to {schema},public on a per-request tenant connection.
Commands
php artisan tenancy:tenant:create {slug} {--domain=} {--schema=} {--team-id=}php artisan tenancy:tenant:delete {id-or-slug}php artisan tenancy:migrate {--fresh} {--seed}
Tests
composer test
License
MIT
Programmatic Tenant Creation (Sign-up)
Preferred flow: create a User, then create a Team for that user. The package provisions the tenant schema via the Team observer and automatically runs tenant migrations.
use PgTenancy\Models\Team; // After creating $user $team = Team::createForUser('Acme Inc', $user); // A tenant record is created and schema is provisioned automatically (observer)
Add tenancy to your registration flow (Livewire Volt example)
- Ensure team-based tenancy mode:
// config/tenancy.php return [ 'mode' => 'team', ];
- Register route middleware so tenancy resolves after auth:
// bootstrap/app.php ->withMiddleware(function (\Illuminate\Foundation\Configuration\Middleware $middleware) { $middleware->alias([ 'tenant' => \PgTenancy\Http\Middleware\IdentifyTenant::class, ]); }) // routes/web.php Route::view('dashboard', 'dashboard')->middleware(['auth', 'tenant', 'verified']);
- Extend your register component to accept a team name and create the team after user creation:
// resources/views/livewire/auth/register.blade.php (excerpt) use PgTenancy\\Models\\Team; public string $team_name = ''; public function register(): void { // ... validate + create $user + Auth::login($user) $teamName = trim($this->team_name) !== '' ? $this->team_name : ($user->name . "'s Team"); Team::createForUser($teamName, $user); // redirect to dashboard } // Add an input to the form <flux:input wire:model="team_name" :label="__('Team name')" type="text" autocomplete="organization" />
- Show current tenant schema (optional):
// resources/views/dashboard.blade.php (excerpt) $schemaName = DB::selectOne('select current_schema() as schema')->schema ?? null;
Notes:
- On
TenantCreated, the package runs tenant migrations indatabase/migrations/tenanton the tenant connection. - Team slugs and tenant schemas are made unique automatically (even for duplicate team names).