Weave 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

Multi Tenancy Laravel Package

swp/multi-tenancy

A Laravel package for adding multi-tenancy to your application, helping isolate tenant data and scope models, routes, and configuration per tenant. Designed to integrate into existing Laravel projects with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer and check the constraint first — the 2018 tag targets older PHP/Symfony versions, so verify it resolves against your runtime before anything else.

composer require swp/multi-tenancy

Where to look first:

  1. The tenant context object. Every multi-tenancy package has one concept to anchor everything else: an object representing "the current tenant." Find the class that holds tenant identity and the singleton/service that serves it. In this package it is exposed through the container and is the thing your code will read from day-to-day.
  2. The resolver/provider layer. These are the classes that decide which tenant applies to an incoming request — subdomain, header, path prefix, or authenticated user. Read these before writing your own, because most day-one work is "our tenancy rule is slightly different."
  3. The DI configuration. Confirm how the package registers itself (Symfony bundle vs. plain service config). This tells you the extension points you can override without forking.
  4. The README and tests. With a single star and no dependents, the test suite is the de facto documentation. Read the resolver tests to learn the expected input shapes.

Your first concrete use case should be the simplest one: resolve a tenant from the request host and expose it as a service. Wire the middleware/event listener, resolve acme.example.com to a tenant record, then inject the context into one controller and assert the tenant name comes back. Do not attempt database switching on day one — prove the resolution path end-to-end first, because that is the part you will customize most.

Implementation Patterns

Middleware-based resolution with a request-scoped context. The canonical flow is: an early middleware resolves the tenant from the request, populates the context, the rest of the request reads from the context, and a terminating step clears it. Follow this rather than threading a $tenant argument through every call — it keeps existing controllers and services untouched.

Inject the context, not the tenant. Have application services depend on the tenant-context interface and pull the current tenant at call time. Injecting a concrete Tenant model at construction time will break the moment you run in a worker that serves multiple tenants or write a test that needs a different tenant per case.

Connection switching for database-per-tenant. If you are isolating by database, the pattern is a listener that reads the tenant's connection config from the resolved tenant and swaps the Doctrine/PDO connection before the first query. Register it to run after tenant resolution and make sure it is idempotent — it will be called more than once in console and queue contexts.

Schema-per-tenant alternative. If tenants share a database, do not rely on the package alone. Pair it with a query-scoping layer (Doctrine filter, Eloquent global scope, or a repository base class) that appends the tenant discriminator to every query. The tenancy package gives you identity; it usually does not give you enforcement.

Resolution strategy chain. Implement tenant-specific rules by registering your own resolver that runs before the package default, returning null to defer to the next resolver in the chain. This is cleaner than subclassing the default resolver, and it makes "internal staff can impersonate a tenant via header" a small, isolated addition.

Console and queue integration. Anything that runs outside HTTP needs an explicit tenant source: a --tenant= option, a job payload field, or a loop that iterates tenants. Wrap the unit of work in a helper that sets the context, runs the callback, and clears the context in a finally block.

Testing helper. Build a small trait that calls the context setter in setUp and clears it in tearDown. Almost every test in a multi-tenant app needs a tenant, and getting this into your base test case early saves repetitive boilerplate.

Gotchas and Tips

Stale package, check the platform requirements. The last release is mid-2018. Expect PHP 7-era syntax and Symfony 3/4 service definitions. If you are on PHP 8+, run the suite immediately and be prepared for deprecation noise or genuine incompatibilities in the resolver internals. Pin the version and treat upgrades as a fork.

AGPL-3.0 is a real constraint. This is a network-copyleft license. If you are building a hosted service on top of it and modifying the package, you are in territory most commercial teams need legal review for. Confirm this before it becomes load-bearing in your architecture.

Context leakage in long-running processes. The classic bug: a queue worker or Octane/RoadRunner worker handles tenant A, then tenant B, and something cached or memoized under A survives. Never store the resolved tenant in a static property or a container singleton that outlives the request cycle. Explicitly clear the context at the end of every job.

Cache keys must be tenant-scoped. Anything you put in Redis or the filesystem needs the tenant identifier in the key prefix. This will silently produce cross-tenant data exposure otherwise, and it will not be caught by functional tests that only ever run one tenant.

Session, logs, and uploads are tenancy surfaces too. Decide early whether session cookies are host-scoped (which usually gives you this for free) and add the tenant to your log context so support can trace a request. Upload paths need a tenant segment or you will eventually have a filename collision.

Debugging resolution failures. Add a single debug log line where the tenant is resolved, printing host, resolver name, and result. Nine out of ten "wrong data" bugs are a resolution miss that silently falls through to a default tenant — and a silent default is the worst design choice you can make here. Fail loudly instead.

Verify the connection at boot, not at first query. After switching connections, assert the expected database name. A misconfigured tenant record will otherwise let reads succeed against your default database, which is the most dangerous failure mode in database-per-tenant setups.

Extension points to favor. Custom resolvers, context decorators, and event listeners on the resolution lifecycle are the safe customization seams. Avoid overriding the container definition of the context itself unless you are prepared to re-apply that override on every package update — and given the release cadence, you probably are.

Migrate per tenant deliberately. Schema-per-tenant means migrations run N times. Build a migration command that iterates tenants, runs migrations, and reports per-tenant failures — do not rely on a single global migrate.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons