PHPackages                             laymont/postgres-multi-tenant - 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. [Framework](/categories/framework)
4. /
5. laymont/postgres-multi-tenant

ActiveLibrary[Framework](/categories/framework)

laymont/postgres-multi-tenant
=============================

Laravel package for Postgres schema-per-tenant multi-tenancy

v0.1.0(1mo ago)00MITPHPPHP ^8.2CI passing

Since May 1Pushed 1w agoCompare

[ Source](https://github.com/laymont/postgres-multi-tenant)[ Packagist](https://packagist.org/packages/laymont/postgres-multi-tenant)[ RSS](/packages/laymont-postgres-multi-tenant/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (9)Versions (2)Used By (0)

laymont/postgres-multi-tenant
=============================

[](#laymontpostgres-multi-tenant)

Este paquete proporciona una base para implementar **multi-tenancy schema-per-tenant** en **PostgreSQL** para proyectos Laravel **12/13**, con foco en buenas prácticas, tipado estricto y testabilidad.

Objetivo
--------

[](#objetivo)

- Cambiar dinámicamente el `search_path` de PostgreSQL por request/job/command.
- Proveer una capa de resolución del tenant (domain/subdomain/header/path/etc.) sin acoplarlo a una app específica.
- Mantener el código del consumidor lo más limpio posible (SRP/DIP), exponiendo contratos claros.

Enfoque
-------

[](#enfoque)

Este paquete implementa el patrón probado en producción para Postgres schema-per-tenant:

- **TenantContext**: estado del schema actual.
- **TenantSchemaManager**: aplica `search_path` (config + SQL) y permite volver a `public`.
- **Listeners**:
    - `ConnectionEstablished`: re-aplica `search_path` al reconectar.
    - `TransactionBeginning`: aplica `SET LOCAL search_path` al iniciar transacción.
- **Guardrail opcional**: validación de `current_schema()` vs schema esperado.

Garantías anti-fuga (lo más importante)
---------------------------------------

[](#garantías-anti-fuga-lo-más-importante)

- El `search_path` se aplica en conexión (`ConnectionEstablished`) y se re-sincroniza si se pierde.
- En cada transacción se aplica `SET LOCAL search_path` para reforzar aislamiento.
- El middleware puede ejecutar un **guardrail** que compara `current_schema()` con el schema esperado.
- En entornos con workers persistentes (ej: Octane), el middleware hace **reset a `public`** en `terminate()`.
- Opcionalmente, antes de **cada query** se re-aplica el `search_path` esperado (auto-healing) para proteger contra modificaciones fuera de banda.

Config:

- `apply_search_path_before_query`: `true` (default)

Resolución de Tenant (baja fricción)
------------------------------------

[](#resolución-de-tenant-baja-fricción)

Por defecto, el paquete resuelve el schema desde el header:

- `X-Tenant-Schema: tenant_acme`

Puedes cambiarlo definiendo `postgres-multi-tenant.tenant_resolver` con una clase que implemente `Laymont\PostgresMultiTenant\Contracts\TenantResolver`.

Resolvers incluidos:

- `Laymont\PostgresMultiTenant\Resolvers\HeaderTenantResolver`
- `Laymont\PostgresMultiTenant\Resolvers\AuthUserTenantResolver`

Middleware recomendado
----------------------

[](#middleware-recomendado)

Middleware incluido:

- `Laymont\PostgresMultiTenant\Http\Middleware\SwitchTenantSchema`

Config clave:

- `unresolved_tenant_mode`: `landlord` (default) o `deny`
- `reset_to_landlord_on_terminate`: `true` (default)

Jobs (Laravel Queue)
--------------------

[](#jobs-laravel-queue)

Este paquete se apega al marco de Laravel:

- La **persistencia de la cola** (ej: tabla `jobs`) debe vivir en el **schema global** (`public`).
- La **ejecución** del job se hace en el **schema del tenant** (cambiando `search_path`) y luego se resetea a `public`.

Para eso se incluye un Job Middleware compatible con Laravel:

- `Laymont\PostgresMultiTenant\Queue\Middleware\RunJobInTenantSchema`

Y un contrato para jobs tenant-aware:

- `Laymont\PostgresMultiTenant\Contracts\TenantAwareJob` (método `tenantSchema(): ?string`)

Migraciones (Laravel Migrations)
--------------------------------

[](#migraciones-laravel-migrations)

Este paquete también se apega al marco de Laravel:

- Laravel controla el catálogo global con su tabla `migrations` en `public`.
- Para cada tenant, al ejecutar migraciones con `search_path` apuntando al schema del tenant, Laravel crea/usa una tabla `migrations` **dentro del schema del tenant**.

Comando incluido:

- `php artisan tenant:migrate {schema}`

Compatibilidad
--------------

[](#compatibilidad)

- PHP: `^8.2`
- Laravel: `^12.0|^13.0`

Instalación
-----------

[](#instalación)

```
composer require laymont/postgres-multi-tenant
```

Implementación (proyecto nuevo)
-------------------------------

[](#implementación-proyecto-nuevo)

### 1) Publica la configuración

[](#1-publica-la-configuración)

```
php artisan vendor:publish --tag="laymont-postgres-multi-tenant-config"
```

### 2) Configura el comportamiento del paquete

[](#2-configura-el-comportamiento-del-paquete)

Edita `config/postgres-multi-tenant.php`.

Recomendado (anti-fuga por defecto):

- `connection`: `pgsql`
- `search_path_schemas`: `['{tenant}', 'public']`
- `enforce_schema_guardrail`: `true`
- `reset_to_landlord_on_terminate`: `true`
- `apply_search_path_before_query`: `true`

Nota: el paquete prioriza `config()` (cache-safe). En producción debes usar `php artisan config:cache` como en cualquier app Laravel.

### 3) Decide cómo resolver el tenant

[](#3-decide-cómo-resolver-el-tenant)

Opción recomendada (API):

- Header `X-Tenant-Schema: tenant_acme`

Si necesitas otra estrategia, define `tenant_resolver` con una clase que implemente:

- `Laymont\PostgresMultiTenant\Contracts\TenantResolver`

### 4) Registra el middleware

[](#4-registra-el-middleware)

El middleware incluido es:

- `Laymont\PostgresMultiTenant\Http\Middleware\SwitchTenantSchema`

Ejemplo (Laravel 12/13): agrega el middleware donde tu aplicación registre middleware (por ejemplo, a nivel de rutas o grupo de rutas).

Recomendación:

- Aplica este middleware **solo** a las rutas tenant-aware (no necesariamente a todo el proyecto).

### 5) Define el contrato de “schema name”

[](#5-define-el-contrato-de-schema-name)

Recomendación: usa un patrón de schemas consistente (por ejemplo `tenant_acme`) y mantén el regex en:

- `schema_pattern`

Esto es una protección contra esquemas inválidos y reduce vectores de fuga.

Implementación (proyecto existente)
-----------------------------------

[](#implementación-proyecto-existente)

### 1) Asegura tu conexión `pgsql`

[](#1-asegura-tu-conexión-pgsql)

Verifica que tu `config/database.php` (o la configuración equivalente) use PostgreSQL y que la conexión que vaya a operar en modo tenant sea la misma que definiste en:

- `postgres-multi-tenant.connection`

### 2) Evita fugas por workers persistentes

[](#2-evita-fugas-por-workers-persistentes)

Si usas Octane o workers persistentes:

- Mantén `reset_to_landlord_on_terminate=true`
- Mantén `apply_search_path_before_query=true`

### 3) Adopta gradualmente

[](#3-adopta-gradualmente)

Puedes empezar aplicando el middleware solo a un subset de endpoints tenant-aware.

Jobs (Laravel Queue) - implementación
-------------------------------------

[](#jobs-laravel-queue---implementación)

Principio: **cola global** (tabla `jobs` en `public`) + **ejecución tenant-aware**.

Para que un job sea tenant-aware, implementa:

- `Laymont\PostgresMultiTenant\Contracts\TenantAwareJob`

Y agrega el middleware al job:

- `Laymont\PostgresMultiTenant\Queue\Middleware\RunJobInTenantSchema`

El middleware asegura:

- switch a tenant
- guardrail
- reset a landlord en `finally`

Migraciones - implementación
----------------------------

[](#migraciones---implementación)

Para migrar un schema tenant:

```
php artisan tenant:migrate tenant_acme
```

Esto ejecuta `migrate` de Laravel dentro del contexto del tenant, permitiendo que Laravel cree y use:

- `tenant_acme.migrations` (tabla por tenant)

Verificación rápida (debug)
---------------------------

[](#verificación-rápida-debug)

En Postgres puedes verificar el schema actual con:

```
select current_schema();
```

En runtime, el guardrail del paquete compara `current_schema()` contra el schema esperado cuando está habilitado.

Configuración
-------------

[](#configuración)

Publicar configuración:

```
php artisan vendor:publish --tag="laymont-postgres-multi-tenant-config"
```

Esto creará `config/postgres-multi-tenant.php`.

Uso
---

[](#uso)

Ver secciones:

- Implementación (proyecto nuevo)
- Implementación (proyecto existente)
- Jobs (Laravel Queue)
- Migraciones (Laravel Migrations)

Licencia
--------

[](#licencia)

MIT.

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance95

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity36

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.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

39d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/13275422?v=4)[Laymont Arratia](/maintainers/laymont)[@laymont](https://github.com/laymont)

---

Top Contributors

[![laymont](https://avatars.githubusercontent.com/u/13275422?v=4)](https://github.com/laymont "laymont (2 commits)")

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/laymont-postgres-multi-tenant/health.svg)

```
[![Health](https://phpackages.com/badges/laymont-postgres-multi-tenant/health.svg)](https://phpackages.com/packages/laymont-postgres-multi-tenant)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45344.0k1](/packages/pressbooks-pressbooks)[fleetbase/core-api

Core Framework and Resources for Fleetbase API

1232.2k16](/packages/fleetbase-core-api)[api-platform/laravel

API Platform support for Laravel

59156.3k10](/packages/api-platform-laravel)[calebdw/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

15104.9k4](/packages/calebdw-larastan)

PHPackages © 2026

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