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 define what happens when switching tenants. Supports single or multiple databases, tenant-aware queued jobs, commands that run per tenant, and easy per-model connection setup.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package: composer require spatie/laravel-multitenancy
  2. Publish the config: php artisan vendor:publish --provider="Spatie\Multitenancy\MultitenancyServiceProvider" --tag="multitenancy-config"
  3. Define your tenant_model in config/multitenancy.php (typically App\Models\Tenant)
  4. Implement the Spatie\Multitenancy\Contracts\IsTenant contract on your Tenant model and add the id, domain, and database attributes (or equivalent)
  5. Configure a tenant_finder (e.g., DomainTenantFinder for domain-based isolation)
  6. Set up at least one switch_tenant_task in config/multitenancy.php — most commonly SwitchDatabaseConnectionTask for per-tenant database switching

Start with the official documentation — particularly the Basic Usage and Tasks sections — and watch the linked LaraCon talk and video for foundational context on multitenancy patterns.


Implementation Patterns

  • Per-tenant database switching: Use SwitchDatabaseConnectionTask to dynamically bind a tenant-specific DB connection at runtime. Define connection patterns in config/database.php using tenant_{$tenantId} or dynamic host/schema resolution.

  • Route caching per tenant: When using tenant-specific routes, leverage SwitchRouteCacheTask and the tenant:artisan wrapper commands to generate and cache routes per tenant (e.g., php artisan tenant:artisan route:cache).

  • Tenant-aware queues & jobs: Use the CanBeUsedByTenant trait on jobs. Jobs dispatched during a tenant context will automatically execute in that tenant context using Spatie\Multitenancy\Jobs\TenantAwareJob.

  • Artisan commands across tenants: Run commands for all tenants using php artisan tenant:artisan db:seed, or for specific tenants with --tenants=1,2,3.

  • Caching isolation: Implement PrefixCacheTask or SwitchRedisPrefixTask to segment cache keys per tenant (e.g., tenant:1:key), avoiding cross-tenant data leakage.

  • Model connection delegation: Use Model::usingTenantConnection($tenant) or Model::onTenant($tenant) to manually set connections for non-request contexts (e.g., seeders, console jobs).

  • Testing tenants: Write tests using usesTenant($tenant) or actingAsTenant($tenant) helpers to simulate tenant context without mocking currentTenant.


Gotchas and Tips

  • Singleton tasks: Your SwitchTenantTask implementations are resolved as singletons — always store original values (e.g., config, DB name) on instance properties in makeCurrent() for restoration in forgetCurrent().

  • Configuration hot-swapping: Be cautious when caching config (config:cache) — SwitchTenantTask modifies config at runtime, but cached config may override dynamic changes. Disable config cache during development or ensure your tasks re-evaluate dynamically.

  • Route cache naming: When shared_routes_cache is true, all tenants must share the same routes — otherwise route mismatches will occur silently. Use tenant:artisan route:clear --tenant=X to clear per-tenant caches.

  • Non-web contexts: Manually set the current tenant with app()->forgetChild('currentTenant'); app()->singleton('currentTenant', fn() => $tenant); when invoking tenant logic outside HTTP requests (e.g., tinker, batch jobs).

  • Validation in tasks: Skip expensive DB lookups in makeCurrent() if the same tenant is already current (check app('currentTenant')).

  • Upgrade gotcha (v4+): Ensure all custom tasks and finders use IsTenant typehints (not Tenant). The old UsesTenantModel trait is deprecated.

  • Performance tip: Use php artisan optimize:clear + tenant:artisan commands to keep route/model caches fresh in multi-database setups.

  • Debug tip: Enable debug in multitenancy.php to log which tasks are executed and in what order — invaluable for troubleshooting silent failures.

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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport