Multi-tenancy is one of those topics where every tutorial shows you the happy path and glosses over the production complexities. After building 5+ multi-tenant SaaS platforms in Laravel, here's what I've actually learned.
The Three Database Strategies
When you're building a multi-tenant app, your first architectural decision is how to isolate tenant data:
1. Database Per Tenant
Maximum isolation. Each tenant gets their own MySQL/PostgreSQL database. Easy to dump, backup, or migrate individual tenants. The downside: provisioning is slower, and you'll hit database connection limits fast if you have thousands of tenants.
// Dynamically switch the database connection per request
config(['database.connections.tenant.database' => $tenant->database_name]);
DB::purge('tenant');
DB::reconnect('tenant');2. Schema Per Tenant (PostgreSQL)
A middle ground. One database, but each tenant gets their own schema (namespace). Works beautifully with PostgreSQL — less supported in MySQL.
3. Shared Database with Tenant ID
The most common for early-stage SaaS. Every table has a tenant_id column, and you scope all queries globally. The risk: forgetting to scope a query and leaking cross-tenant data.
The Package I Recommend
stancl/tenancy handles 80% of the complexity for you — subdomain resolution, database switching, queue tenant awareness. Worth using from day one.
The Queue Problem Nobody Talks About
When a queued job fires, Laravel doesn't automatically know which tenant context to run it in. Without addressing this, you'll get jobs running against the wrong database.
The solution: create a TenantAwareJob middleware:
class TenantAwareMiddleware {\n public function handle($job, $next) {\n $tenant = Tenant::find($job->tenantId);\n tenancy()->initialize($tenant);\n $next($job);\n tenancy()->end();\n }\n}Billing: Don't Reinvent Stripe
Use Laravel Cashier for Stripe subscriptions. Map features to Stripe plans and gate them with a simple $tenant->subscribedToFeature('advanced-reports') check.
Final Advice
Start with shared-database-with-tenant-ID. It's easier to reason about and migrate from when you grow. Move to database-per-tenant only when a customer demands it or you have compliance requirements.