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

dev-main 2025-08-11 17:01 UTC

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

  1. Require the package (adjust VCS path if local):
composer require pg-tennancy/laravel-pg-tenancy
  1. 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
  1. Configure config/tenancy.php and ensure a privileged system_connection can create schemas/roles.

  2. 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 (configure base_domain)
  • Path: example.com/tenant1 (configure path_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)

  1. Ensure team-based tenancy mode:
// config/tenancy.php
return [
    'mode' => 'team',
];
  1. 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']);
  1. 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" />
  1. 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 in database/migrations/tenant on the tenant connection.
  • Team slugs and tenant schemas are made unique automatically (even for duplicate team names).