cortex/tenants
Cortex Tenants brings multi-tenancy to Laravel applications, helping resolve tenants, scope Eloquent queries, and isolate data per tenant. It provides a lightweight foundation for building SaaS or multi-tenant systems within the Cortex ecosystem.
Architecture fit. cortex/tenants implements single-database, shared-schema multi-tenancy: a polymorphic tenantable relation plus a tenant resolver and global query scopes that filter every tenant-owned model by tenant_id. This is a defensible model for a B2B SaaS with many small, similarly shaped tenants where per-tenant cost matters and tenants are not a hard regulatory boundary. It is a poor fit where tenancy is the security or compliance boundary (health, financial, EU data residency), because there is no physical isolation — a single missing scope is a cross-tenant data exposure, not a performance bug. Note also that the description explicitly frames the package as a frontend layer: it is not self-contained. It presumes the surrounding Cortex runtime (cortex/foundation, cortex/auth, cortex/attributes, rinvex/laravel-support) is already installed and version-aligned. Adopting this package means adopting a framework-on-a-framework, not a library.
Integration feasibility. Low as-is. The repository is archived, has 12 stars and zero dependents, and the -classic naming indicates it is the superseded branch of the Cortex line. It will almost certainly not satisfy modern Laravel (10–12) and PHP 8.2+ dependency constraints without patching. Realistically the integration is: fork it into our org, upgrade its Illuminate/Support constraints, and inherit the transitive Cortex dependencies at compatible pinned versions — several of which are likely archived too. This is a sourcing exercise as much as an engineering one.
Technical risk. The dominant risk is silent scope bypass. Global-scope tenancy fails open or leaks in several routine paths: raw DB:: queries, withoutGlobalScope() calls, queued jobs and listeners that run without a tenant context, artisan/console commands, scheduled tasks, package internals with their own query builders, and reporting/analytics joins written outside the scope. Polymorphic tenancy compounds this by making tenant resolution indirect — resolution failures surface as either an exception or, worse, an unscoped result set depending on configuration. Secondary risks: composite index discipline (every query must lead with tenant_id), cache key collisions across tenants, and file-storage key collisions. The package being archived means no upstream fix if a bypass class is discovered.
Key questions to resolve before any decision.
Stack fit. Reasonable if the team is already on Cortex and Laravel 5.x/6.x-era conventions; otherwise the fit is poor and the package drags in opinions (repository pattern, attributes-driven schema, its own auth) that will conflict with a conventional Laravel codebase. The "same database, centrally shared vs. tenant-isolated" model is genuinely useful for shared reference data (countries, currencies, plan catalogues) — that is the strongest argument in its favour.
Migration path. Two distinct cases. (a) Greenfield: add tenant_id to every tenant-owned table from day one, make it the leading column of every composite index, and make tenant resolution a mandatory middleware/queue-middleware concern before the first tenant exists. (b) Retrofit: substantially harder — you must backfill tenant_id across existing tables, rewrite every query and report, audit the codebase for scope bypasses, and re-key caches and storage. Migrating from a database-per-tenant package (stancl/tenancy, spatie/laravel-multitenancy) is a different and larger project: those give physical isolation, and moving to shared schema is a deliberate downgrade in blast radius that should be approved at the architecture level, not the package level.
Compatibility. Treat the upstream as frozen. Pin the fork to an internal version, run it against our actual Laravel/PHP matrix in CI, and vendor the transitive Cortex packages we depend on. Do not expect composer update to be safe.
Sequencing.
Maintenance. We own it. An archived package with 12 stars and no dependents has no patch pipeline, no security advisories, and no compatibility work — every Laravel upgrade, PHP upgrade, and CVE in a transitive dependency becomes our ticket. Budget a standing maintenance allocation, not a one-off integration cost.
Support. Effectively none. There is no maintainer to escalate to and no community to search; internal documentation, a named owning team, and a written runbook are prerequisites, not nice-to-haves. Bus factor is concentrated in whoever performs the fork upgrade.
Scaling. Shared-schema tenancy scales well in tenant count and poorly in tenant skew. Watch three ceilings: (1) index and table bloat as the largest tenant grows — every index must be tenant-leading or performance degrades for everyone; (2) noisy-neighbour effects, since one heavy tenant consumes shared connection pool and I/O; (3) the eventual largest-tenant escape hatch — moving a whale to its own database or partition breaks the single-scope assumption and requires a resolution layer that can route per tenant. If that escape hatch is foreseeable, design the resolver to support it now.
Failure modes to instrument for.
withoutGlobalScope, or third-party packages → detect with static analysis and row-level integration tests.tenantable record silently yielding no tenant; alert on unresolvable context.Ramp-up. Every engineer touching the data layer must internalise the tenancy invariants, which is a persistent cognitive tax that conventional Laravel does not impose. Expect a real onboarding cost and encode the invariants in lint rules, code review checklists, and a test harness — because relying on discipline alone is how this architecture fails.
Recommendation up front: at a 0.09 score, archived status, and near-zero adoption, do not adopt this package as a dependency. If single-DB multi-tenancy is the right architecture, take the pattern (tenant-leading indexes, global scopes, mandatory context middleware, queue middleware) and implement it in-house against a maintained foundation — or evaluate a supported alternative. Revisit the package only if the team is already committed to the Cortex ecosystem and is prepared to own the fork indefinitely.
How can I help you explore Laravel packages today?