← All posts

Dev log · Backend

LaravelDockerSaaS

Building a Multi-Tenant SaaS Backend with Laravel & Docker

10 min read

One of my backend projects is a multi-tenant SaaS API built with Laravel and deployed with Docker. The goal: multiple clients on one deployment, each with isolated data, without running a separate server per customer.

This post explains the architecture choices — not Laravel basics, but the decisions that make multi-tenancy work in production.

Why multi-tenant?

Separate deployments per client don’t scale operationally. You want one codebase, one pipeline, shared monitoring — but hard boundaries so Client A never sees Client B’s data. For a B2B SaaS dashboard and API, that boundary is non-negotiable.

Tenant isolation strategy

I used a shared database, shared schema model with a tenant_id column on tenant-scoped tables. It’s the right trade-off for this project’s scale:

  • Cheaper and simpler to operate than database-per-tenant
  • Easier migrations across all tenants at once
  • Still secure when every query is scoped through middleware

How tenancy is resolved

  1. Request arrives with subdomain, header (X-Tenant-ID), or JWT claim
  2. Tenant middleware resolves the tenant record and binds it to the request context
  3. Global Eloquent scope automatically applies where tenant_id = ? on scoped models
  4. Jobs and queued workers re-hydrate tenant context before handling tasks

Docker setup

  • PHP-FPM — Laravel application container
  • Nginx — reverse proxy, static assets, rate limiting
  • MySQL — primary datastore
  • Redis — cache, sessions, queue backend

docker-compose wires services for local dev. Production uses the same images with environment-specific .env files — no “works on my machine” surprises.

Security checklist

  • Never trust client-supplied tenant_id in the request body — derive from auth token only
  • Encrypt sensitive tenant config at rest
  • Per-tenant rate limits to prevent noisy-neighbor abuse
  • Audit log table for admin actions

When to choose a different model

If you have enterprise clients demanding physical isolation, or strict compliance requiring separate databases, move to database-per-tenant or schema-per-tenant. Start simple unless regulation forces complexity.