Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Multitenancy Laravel Package

spatie/laravel-multitenancy

Unopinionated multitenancy for Laravel. Detect the current tenant per request and run configurable tasks when switching tenants. Supports single or multiple databases, tenant-aware queued jobs, per-tenant Artisan commands, and easy model connection handling.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Multi-Tenant Strategy Alignment: The package supports shared-database, separate-database, and hybrid multitenancy models, making it adaptable to most Laravel-based SaaS architectures. The unopinionated design allows customization of tenant resolution (e.g., subdomains, path-based, or custom logic).
  • Laravel Ecosystem Synergy: Deep integration with Laravel’s service container, middleware, and queue systems ensures minimal friction with existing codebases. Compatibility with Laravel 11+ and PHP 8.2+ aligns with modern stack requirements.
  • Extensibility: Contract-based design (IsTenant, SwitchTenantTask) enables custom tenant models, finders, and tasks without forking the package. This is critical for edge cases (e.g., tenant-specific configurations, dynamic database schemas).

Integration Feasibility

  • Middleware Hooks: Tenant resolution occurs via middleware (Spatie\Multitenancy\Middleware\ResolveCurrentTenant), allowing seamless insertion into Laravel’s pipeline. Existing middleware (e.g., auth, CORS) can coexist without conflicts.
  • Database Agnosticism: Supports MySQL, PostgreSQL, and SQLite out-of-the-box. For separate-database setups, the package provides tenant_connection configuration to dynamically switch database connections per request.
  • Queue System: Tenant-aware jobs are handled via interfaces (TenantAware, NotTenantAware) or config flags, reducing boilerplate for background processing. Closure support ensures flexibility for dynamic tenant contexts.

Technical Risk

  • Performance Overhead:
    • Tenant Resolution: Each request triggers a tenant lookup (e.g., DomainTenantFinder). For high-traffic landlord routes (e.g., /admin), this adds latency. Mitigation: Cache tenant lookups or use a faster resolver (e.g., Redis-based).
    • Database Switching: Separate-database setups require connection switching, which can introduce delays. Test with production-like loads to validate.
  • State Management:
    • Facades/Singletons: Tenant-specific facades (e.g., Cache, Mail) may retain stale instances across tenant switches. Requires explicit clearing (e.g., via SwitchTenantTask).
    • Queue Jobs: Tenant-aware jobs failing due to deleted tenants (CurrentTenantCouldNotBeDeterminedInTenantAwareJob) need retry logic or fallback handling.
  • Migration Complexity:
    • Shared vs. Separate Databases: Shared-database setups require schema design (e.g., tenant_id foreign keys), while separate databases need connection management. Hybrid approaches may complicate deployments.
    • Legacy Code: Existing queries assuming a single tenant (e.g., User::all()) must be updated to scope by tenant (e.g., User::where('tenant_id', $tenant->id)).

Key Questions

  1. Tenant Isolation Requirements:
    • Are tenants fully isolated (separate databases) or shared (schema-based)? This dictates connection management and data security strategies.
    • Are there tenant-specific configurations (e.g., queues, caches, APIs) that require per-tenant initialization?
  2. Performance SLAs:
    • What is the acceptable latency for tenant resolution? Will caching (e.g., Redis) or a custom finder (e.g., API-based) be needed?
  3. Deployment Strategy:
    • How will tenant databases be provisioned (e.g., Flyway, Laravel Migrations)? Will shared schemas use soft-deletes or row-level security?
  4. Observability:
    • How will tenant-specific errors/logs be correlated (e.g., adding tenant_id to logs)? The package lacks built-in tenant context in logs.
  5. Scaling:
    • Will tenant data grow to require sharding or read replicas? The package doesn’t address horizontal scaling of tenant data.
  6. Customization Needs:
    • Are there tenant-specific middleware, routes, or service providers? The package supports this but requires manual implementation.
  7. Testing:
    • How will tenant-specific tests be isolated (e.g., database transactions per tenant)? The package’s test suite uses multiple databases, which may not mirror production.

Integration Approach

Stack Fit

  • Laravel Core: Native integration with Laravel’s service container, middleware, and queue systems ensures minimal stack modifications. The package replaces or extends Laravel’s default behavior without requiring monolithic changes.
  • Database Layer:
    • Shared Database: Works with Laravel’s Eloquent and Query Builder. Requires tenant-aware models (e.g., use Spatie\Multitenancy\Traits\HasTenants).
    • Separate Databases: Uses Laravel’s database connection switching (tenant_connection config). Requires a tenants table with connection details (e.g., database, host).
  • Queue Workers: Supports tenant-aware jobs via interfaces or config. Workers must run with the same Laravel environment (e.g., same .env) to resolve tenants.
  • Caching: Tenant-specific caches (e.g., Redis) require manual management (e.g., prefix keys with tenant ID or clear caches on tenant switch).

Migration Path

  1. Assessment Phase:
    • Audit existing code for tenant assumptions (e.g., global queries, hardcoded configs).
    • Design tenant isolation strategy (shared/separate databases) and map to package features.
  2. Setup:
    • Install the package: composer require spatie/laravel-multitenancy.
    • Publish config: php artisan vendor:publish --provider="Spatie\Multitenancy\MultitenancyServiceProvider".
    • Configure tenant_model, tenant_finder, and database connections in config/multitenancy.php.
  3. Core Integration:
    • Add middleware to app/Http/Kernel.php:
      protected $middlewareGroups = [
          'web' => [
              // ...
              \Spatie\Multitenancy\Middleware\ResolveCurrentTenant::class,
          ],
      ];
      
    • Implement tenant model (e.g., app/Models/Tenant.php) with IsTenant contract.
  4. Database Migration:
    • For shared databases: Add tenant_id to pivot tables or use HasTenants trait.
    • For separate databases: Create a tenants table with connection details and configure tenant_connection in the config.
  5. Feature Rollout:
    • Enable tenant-aware queues (queues_are_tenant_aware_by_default).
    • Implement custom tasks (e.g., cache clearing, facade resetting) via SwitchTenantTask.
    • Update models/jobs to handle tenant contexts (e.g., app(IsTenant::class)->id).
  6. Testing:
    • Use package’s test databases (laravel_mt_landlord, laravel_mt_tenant_*) as a baseline.
    • Implement tenant-specific test isolation (e.g., database transactions, seeders).

Compatibility

  • Laravel Ecosystem:
    • Packages: Most Laravel packages (e.g., Laravel Nova, Cashier) work out-of-the-box if they respect the current tenant context. Exceptions may require tenant-aware wrappers.
    • Auth: Tenant-aware auth (e.g., Auth::user()) works if the users table includes tenant_id. Use Spatie\Multitenancy\Traits\HasTenants for models.
    • APIs: Tenant context is available in API routes via app('currentTenant').
  • Third-Party Services:
    • Stripe/PayPal: Tenant-specific API keys can be stored in tenant models and resolved via app(IsTenant::class)->stripe_key.
    • Mail Services: Tenant-specific mailers require dynamic configuration (e.g., Mail::tenant($tenant->mailer)).
  • Legacy Systems:
    • Non-Laravel services (e.g., legacy PHP, Node.js) must pass tenant context explicitly (e.g., via headers or subdomains).

Sequencing

  1. Phase 1: Landlord Routes
    • Implement tenant management (CRUD) for landlord users (e.g., /admin/tenants).
    • Use Tenant::all() and manual tenant switching ($tenant->makeCurrent()).
  2. Phase 2: Tenant-Aware Frontend
    • Add ResolveCurrentTenant middleware to web routes.
    • Update frontend to read app('currentTenant') for tenant-specific data.
  3. Phase 3: Background Jobs
    • Enable tenant-aware queues and update jobs to handle tenant contexts.
  4. Phase 4: Advanced Features
    • Implement custom tasks (e.g., cache clearing, facade resets).
    • Add tenant-specific configurations (e.g., queues, APIs).
  5. Phase 5: Observability
    • Instrument logs/metrics with tenant IDs (e.g., Log::withContext(['tenant_id' => app('currentTenant')?->id])).

Operational Impact

Maintenance

  • Configuration Drift:
    • Risk: Tenant-specific configurations (e.g., queues, APIs) may diverge across tenants. Mitigation: Use tenant model attributes (e.g., tenant->queue_connection) and validate via `SwitchTenant
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony