CÓMO CONSTRUIR APLICACIONES MULTI-TENANT CON LARAVEL

Multi-tenant en Laravel es un patrón de arquitectura que permite que una sola aplicación Laravel, una sola instalación, sirva de forma simultánea a múltiples clientes, empresas u organizaciones, llamados tenants o inquilinos, pero manteniendo los datos, usuarios, configuraciones y lógica de cada uno completamente aislados y separados entre sí.
  • Decidir la estrategia de aislamiento de datos
    Estrategia Aislamiento Complejidad Costo DB Recomendado para (2026) Paquete más usado actualmente
    Single Database Lógico (tenant_id) ★☆☆ Muy bajo Proyectos pequeños/medianos, rápido prototipo spatie/laravel-multitenancy o tenancyforlaravel (modo single)
    Database per Tenant Físico (BD separada) ★★★ Alto SaaS serios, GDPR/HIPAA, alta seguridad stancl/tenancy (archtechx/tenancy)
    Schema per Tenant Físico (esquema) ★★☆ Medio Buen balance (PostgreSQL recomendado)
    • Si se busca rapidez y simplicidad → empezar con single database + spatie/laravel-multitenancy
    • Si se planea un SaaS real con crecimiento → es mejor stancl/tenancy (Database per Tenant o Schema). Es el paquete más maduro, mantenido y con más features out-of-the-box.
  • Paquetes recomendados
    Paquete Autor Tipo más fuerte Estrellas GitHub (aprox) Comunidad activa Recomendado si...
    stancl/tenancy Samuel Štancl Database / Schema ~3.5k+ Muy alta Quieres el paquete más completo y automático
    spatie/laravel-multitenancy Spatie Single DB (muy flexible) ~2.8k+ Muy alta Proyecto simple o ya tienes single DB
    tenancy/tenancy (viejo) Baja
  • Implementación recomendada con stancl/tenancy (Database per Tenant)
    • Paso 1: Instalación

      composer create-project laravel/laravel saas-app
      cd saas-app
      composer require stancl/tenancy
      
    • Paso 2: Publicar e instalar

      php artisan tenancy:install
      
      Esto crea:Modelo Tenant por defecto, migraciones central y tenant y un fichero de configuración "config/tenancy.php".
    • Paso 3: Configura identificación del tenant (lo más común es por subdominio)

      // config/tenancy.php
      'central_domains' => [
          'localhost',
          '127.0.0.1',
          'saas-app.test',
      ],
      
      'identification' => [
          'by' => 'subdomain',          // o 'domain', 'path', 'header', etc.
      ],
      
    • Paso 4: Personaliza el modelo Tenant (muy recomendado)

      
      // app/Models/Tenant.php
      namespace App\Models;
      
      use Stancl\Tenancy\Database\Models\Tenant as BaseTenant;
      use Stancl\Tenancy\Contracts\TenantWithDatabase;
      use Stancl\Tenancy\Database\Concerns\HasDatabase;
      use Stancl\Tenancy\Database\Concerns\HasDomains;
      
      class Tenant extends BaseTenant implements TenantWithDatabase
      {
          use HasDatabase, HasDomains;
      
          protected $fillable = ['id', 'name', 'plan', 'data']; // agrega lo que necesites
      }
      
    • Paso 5: Migra bases de datos

      # Migraciones centrales (users globales, tenants, etc.)
      php artisan migrate
      
      # Crea una base de datos de prueba para un tenant
      php artisan tenants:seed --class=DatabaseSeeder
      
    • Paso 6: Rutas multi-tenantphp
      // routes/tenant.php  (creado automáticamente)
      Route::middleware(['web', 'tenancy'])->group(function () {
          Route::get('/', function () {
              return 'Bienvenido al dashboard de ' . tenant('name');
          });
      });
      
    • Paso 7: Crear un tenant (ejemplo en un controlador o seeder)

      
      use App\Models\Tenant;
      use Stancl\Tenancy\Database\Models\Domain;
      
      $tenant = Tenant::create([
          'id' => 'acme',
          'name' => 'Acme Corp',
      ]);
      
      $tenant->domains()->create(['domain' => 'acme.localhost']);
      
      Ahora accede a http://acme.localhost:8000 → verás solo los datos de ese tenant.
  • Features útiles que casi todos usanFiltrado automático de datos (ya lo hace el paquete).
    • Jobs y Queues tenant-aware → configurado por defecto.
    • Storage tenant-specific → storage_path('app/public/' . tenant('id')).
    • Migrations por tenant → php artisan tenants:migrate.
    • Comandos masivos → php artisan tenants:seed, tenants:cache:clear, etc..
  • Alternativa: Single Database con SpatieSi prefieres empezar simple:

    composer require spatie/laravel-multitenancy
    
    php artisan vendor:publish --provider="Spatie\Multitenancy\MultitenancyServiceProvider" --tag="migrations"
    php artisan migrate
    
    Luego usar traits como HasTenant en tus modelos y scopes globales.