stancl/tenancy: automatic multi-tenancy for Laravel without touching your app code
Automatic multi-tenancy for Laravel. No code changes needed.
At a glance
- What is it?
- Stancl's Tenancy package lets a Laravel application serve many tenants from one codebase by swapping the database and cache connections at runtime instead of rewriting models. It fits teams that already have a working single-tenant Laravel app and want hostname-based tenants.
- Who is it for?
- Adopt stancl/tenancy if you have a working single-tenant Laravel application and want to add hostname-based tenants without rewriting model traits, Cache calls or Storage calls, and you are comfortable with the package bootstrapping tenancy for you. Do not adopt it if your tenants must share one database with row-level scoping, or if you need a framework-agnostic tenancy layer outside PHP.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What stancl/tenancy actually solves for a Laravel SaaS
A Laravel application that starts as a single-tenant product usually hardcodes one database connection, one cache store and one filesystem disk. Turning that into a product where each customer gets an isolated database normally means threading a tenant identifier through every model, every query and every cache call. stancl/tenancy takes the other route: it keeps the application code as it is and changes what the framework resolves at runtime.
The README states the promise directly: "You won't have to change a thing in your application's code." It lists three concrete claims behind that sentence. There are no model traits to change the database connection. There is no replacing of Laravel classes such as Cache and Storage with tenancy-aware equivalents. And tenant identification based on hostname, including second level domains, is built in.
The audience is therefore narrow and specific: a PHP team on Laravel that already has a functioning single-tenant application and wants each tenant to have its own database, without a refactor of the domain layer. If your tenants are expected to share one database with a tenant_id column on every table, this package is aimed at the opposite problem.
How the package swaps connections instead of rewriting models
The design rests on Laravel's service container and its connection resolution. Rather than asking the developer to declare a tenant-aware base model, the package hooks into the framework's bootstrapping and reconfigures the default database and cache connections for the current request. That is why the README can say no model traits are needed: the model still asks for the default connection, and the default connection has already been pointed at the tenant's database.
The same reasoning explains the second claim. Cache and Storage are not replaced with tenancy-aware subclasses, because there is nothing tenant-specific in the call site to replace. The underlying store is switched, and the call looks unchanged.
Tenant identification is the entry point. The README says hostname-based identification, including second level domains, is built in. In practice that means the domain in the incoming request decides which tenant is loaded, so a tenant can be reached at a subdomain or at a custom domain without a separate route group.
The repository layout is consistent with a package that has to prove this across many backends rather than one. docker-compose.yml defines mysql, mysql2, postgres, redis, mssql, memcached and dynamodb services, and the test container waits on health checks for all of them. The Dockerfile installs pdo_mysql, pdo_pgsql, sqlite, redis, memcached and, for PHP 8.5, builds pdo_sqlsrv from source. The package is tested against that spread, which tells you the connection-swapping approach is not tied to a single database engine.
Getting stancl/tenancy into a Laravel app
The README does not reproduce install steps. It points at the documentation site at https://v4.tenancyforlaravel.com, and its version badge links to packagist.org/packages/stancl/tenancy, which is where the package name comes from. There is no composer command written in the README, so the honest starting point is the documentation site rather than a command copied from here.
What the repository does give you is the environment the maintainers run the package against. The test container in docker-compose.yml is built from the repository's own Dockerfile, which installs pdo_mysql, pdo_pgsql, sqlite, redis, memcached and, when PHP_VERSION contains 8.5, builds pdo_sqlsrv from source. The compose file defines mysql, mysql2, postgres, redis, mssql, memcached and dynamodb services, and the test service waits on health checks for each of them before it starts.
The environment passed to the test container is the clearest picture of what the package expects to find at runtime:
environment:
DOCKER: 1
DB_PASSWORD: password
DB_USERNAME: root
DB_DATABASE: main
TENANCY_TEST_REDIS_HOST: redis
TENANCY_TEST_MYSQL_HOST: mysql
TENANCY_TEST_PGSQL_HOST: postgres
TENANCY_TEST_SQLSRV_HOST: mssql
TENANCY_TEST_SQLSRV_USERNAME: sa
TENANCY_TEST_SQLSRV_PASSWORD: P@sswordThose keys tell you the package is exercised against MySQL, PostgreSQL, SQL Server and Redis, with SQL Server reached through the sa account. The test container also mounts the repository at ${PROJECT_PATH:-$PWD} and sets its working directory to the same path, so the suite runs against your checkout rather than a copy inside the image.
For a first real use, the shape of the workflow is: create a tenant record with a domain, then load the application through that domain. The README does not show the tenant creation API, so follow the v4 documentation for the exact method names rather than guessing. What you should be able to confirm afterwards is that a request to the tenant's hostname resolves to the tenant's database, and that a request to a different hostname resolves to a different one.
Where the automatic approach breaks down
The central trade-off is that tenancy is bootstrapped for you, which means the moments when it is not bootstrapped are the moments you have to think about. A queued job that runs in a worker process, a scheduled command, or a long-running process outside the HTTP request lifecycle does not automatically carry the tenant context that a web request does. The README does not document rollback, nor does it describe how queue workers should be configured, so treat those as questions to answer from the v4 documentation before you build on them.
Second, the package assumes database-per-tenant isolation. If your product requires all tenants in one schema with row-level scoping, or if you need cross-tenant reporting to be a simple join, this design works against you. The connection swap is the whole mechanism, and there is no shared-database mode described in the README.
Third, hostname identification with second level domain support is convenient but it fixes your tenancy key to DNS. A product where tenants are identified by an API key, a header, or a path segment rather than a domain is not what the README advertises as built in, and you would be working against the grain.
Finally, the README is short by design and defers to the documentation site. Anything you cannot find in the README, including upgrade paths between major versions, lives there or nowhere. The README itself does not document rollback or downgrade steps.
How this differs from building tenancy by hand or using a shared-database package
The realistic alternative for a Laravel team is not another package but a hand-rolled tenancy layer: a base model with a connection resolver, a middleware that reads the tenant from the request, and explicit calls to switch the cache and filesystem where needed. That approach gives you full control and no dependency, at the cost of touching every place the framework resolves a connection. The difference is where the work lands. Hand-rolled tenancy puts the burden on your application code and your reviewers; stancl/tenancy puts it in the framework's bootstrapping, which is why the README can claim no model traits and no replaced classes.
The other alternative is a shared-database multi-tenancy package, where every tenant's rows sit in the same tables behind a tenant_id column. That is a different data model, not a different implementation of the same one. Shared-database tenancy makes cross-tenant analytics and migrations simpler and makes per-tenant backup, restore and deletion harder. stancl/tenancy's connection-swapping model makes per-tenant databases the unit of isolation, which is closer to what regulated customers usually ask for, and makes cross-tenant queries a matter of iterating tenants rather than writing one query.
Neither is strictly better. The choice is whether your isolation boundary is a column or a database, and the package is built entirely around the second.
Maintenance, versions and the MIT licence
The repository is not archived and the last push was on 2026-09-21, two days before this writing. Recent releases are v3.10.1 on 2026-08-05, v3.10.0 on 2026-03-18 and v3.9.1 on 2025-03-13. That cadence is worth reading carefully: two releases in 2026 and one in 2025, with a patch landing in August 2026. The README's badge advertises Laravel 10.x even though the alt text says 11.x, and the documentation link points at v4.tenancyforlaravel.com while the README's own links point at the 3.x branch on GitHub. That mismatch between the advertised major and the documented major is the single most important thing to check before you pin a version.
Upgrade cost is the real maintenance question for a package that reaches into framework bootstrapping. Because the package swaps connections rather than asking you to change models, a Laravel major upgrade is mostly the package's problem to solve, not yours. But it also means a package release can change behaviour your application depends on without any diff in your own code. The repository's phpstan.neon, phpunit.xml and the multi-backend docker-compose.yml suggest the maintainers invest in static analysis and integration testing, which is the mitigation for that risk.
The licence is MIT. That is permissive: you can use the package in commercial and closed-source products, and you are not required to publish your own changes. It does not, by itself, settle questions about the licences of the database drivers or services you connect to, and it is not legal advice about your specific distribution.
Editorial conclusion
Adopt stancl/tenancy if you have a working single-tenant Laravel application and want to add hostname-based tenants without rewriting model traits, Cache calls or Storage calls, and you are comfortable with the package bootstrapping tenancy for you. Do not adopt it if your tenants must share one database with row-level scoping, or if you need a framework-agnostic tenancy layer outside PHP. Before committing, verify in a staging environment that your queue workers and scheduled commands behave correctly when tenancy is bootstrapped, because the README does not document those boundaries and the repository layout only shows the test suite covering MySQL, PostgreSQL, MariaDB, SQL Server, Redis, Memcached and DynamoDB through docker-compose.yml.
Frequently asked questions
Does stancl/tenancy require changes to my Laravel models?
No. The README states there are no model traits to change the database connection, and no replacing of Laravel classes such as Cache and Storage with tenancy-aware classes. The package handles the switch at the framework level instead.
How does stancl/tenancy identify which tenant a request belongs to?
The README says tenant identification based on hostname, including second level domains, is built in. That means the domain on the incoming request determines the tenant.
Which Laravel version does stancl/tenancy support?
The README's badge image advertises Laravel 10.x while its alt text says 11.x, and the documentation link points to v4.tenancyforlaravel.com while the repository links point at the 3.x branch. Confirm the supported version on the documentation site before pinning a release.
What licence is stancl/tenancy released under?
The repository lists the MIT licence. That permits commercial and closed-source use without a requirement to publish your own modifications.
What databases can stancl/tenancy run tenants on?
The repository's docker-compose.yml defines mysql, mysql2, postgres, redis, mssql, memcached and dynamodb services for the test suite, and the Dockerfile installs pdo_mysql, pdo_pgsql and sqlite extensions plus pdo_sqlsrv for PHP 8.5. The README itself does not list supported engines.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/archtechx-tenancy)