Engineering

A Practical Guide to Multi-Tenant Laravel Architecture

Hayden JacksonHayden Jackson
2 min read
PHP source code with syntax highlighting in a code editor

For most B2B SaaS products, the right starting point for multi-tenancy is a single database with a tenant_id column and a global scope — not a database-per-tenant split. Database-per-tenant solves a problem most teams don't have yet and creates several they will: migration fan-out, cross-tenant reporting pain, and connection-pool exhaustion at scale.

Enforce tenancy at the model layer, not the controller layer

The most common multi-tenant bug is a controller or job that forgets to scope a query. Fix the failure mode at the source with a global scope so it's structurally impossible to forget.

class BelongsToTenant extends Model
{
    protected static function booted(): void
    {
        static::addGlobalScope('tenant', function (Builder $query) {
            if ($tenantId = app(CurrentTenant::class)->id()) {
                $query->where('tenant_id', $tenantId);
            }
        });

        static::creating(function (self $model) {
            $model->tenant_id ??= app(CurrentTenant::class)->id();
        });
    }
}

Index for tenancy from day one

Every tenant-scoped table needs a composite index that leads with tenant_id — otherwise queries that look fast in development degrade badly once a handful of large tenants share the table. Pair that with row-level constraints (unique indexes scoped to tenant_id) so uniqueness rules can't leak across tenants.

  1. Add tenant_id to every tenant-owned table, indexed as the leading column
  2. Enforce scoping with a global scope, not per-query discipline
  3. Scope uniqueness constraints to tenant_id explicitly
  4. Move to schema- or database-per-tenant only when a customer requires physical isolation for compliance
Should I use separate databases for each tenant in Laravel?

Only when a customer contractually requires physical data isolation. Otherwise, row-level tenancy with a global scope is simpler to operate, cheaper to run, and easier to report across.

Get an architecture review

Share X LinkedIn
Hayden Jackson

Hayden Jackson

Get engineering notes in your inbox

Practical AI, cloud, and security delivery notes - no fluff, no sales spam.

Keep reading

Related posts

Software developers working at desks with laptops and monitors showing code in an office
Engineering9 min read

From monolith to modular services without stopping delivery

How to move from a monolith to modular services without pausing delivery: start with a modular monolith, find the seams, use the strangler fig pattern, migrate data safely, and release behind feature flags with observability and a tested rollback.

Hayden Jackson
Hayden Jackson