Skip to main content
Tutorial

Laravel Multi-Tenancy: How I Built One Platform for 12 UAE Businesses

4 min read

How a single Laravel codebase now serves 12 UAE businesses through multi-tenancy.

Laravelmulti-tenancyUAE developmentPHPTenancy

Last month, I delivered a Laravel application that serves 12 different businesses across the UAE, all from a single codebase. The client was a franchise network in Dubai — their old system required separate dashboards for each branch, which made updates a nightmare. They wanted everything unified. I proposed multi-tenancy. Here’s what actually worked.

The Multi-Tenancy Decision

Let’s be real: multi-tenancy isn’t always the right call. If your clients have wildly different requirements, you’ll dig yourself into a configuration mess. But in this case, all 12 businesses operated under the same core structure — think retail franchises with similar inventory and staff management needs. The upside of sharing a codebase was obvious: easier updates, centralized monitoring, and cost-effective maintenance.

I spent two days researching packages. Laravel’s core doesn’t include multi-tenancy, so I benchmarked landlord vs Stancl’s Tenancy. The deciding factor? Stancl’s support for separate PostgreSQL databases per tenant aligned with UAE data privacy laws requiring customer data isolation.

Database Structure: Why Separate DBs Won?

We initially tried a shared database with tenant_id columns, then switched to separate databases. The tipping point came when testing performance at scale — a client’s test dataset with 200k+ records per tenant caused query times to spike by 40% in shared mode. Isolation gave us better speed guarantees (plus easier backups/destroyal).

Here’s the setup:

  • Tenant identification via subdomains (business1.platform.ae, business2.platform.ae)
  • PostgreSQL DB per tenant
  • Shared Redis cache for global lookup tables
  • UUIDs instead of auto-incrementing IDs to avoid collision risks

Migration Hell and How We Survived

First major snag: seeding data. Laravel’s factories didn’t respect dynamic database connections out-of-box. I spent 12 hours fighting with custom factory resolver classes before finding a workaround using DB::setTablePrefix() in the tenant bootstrapping layer.

Even worse: forgetting to include the tenant ID when setting up a foreign key between inventory items and suppliers. That caused a cascade of errors when business A’s staff accessed business B’s supply list, and cost me two days of debugging.

UAE Localization: Arabic + Hijri Dates

Twelve tenants meant twelve config files for localization. But here’s the catch: four clients required Arabic interfaces with Hijri calendars. I added a tenant-config/{tenant_id}/lang/ directory structure, and used Laravel’s setlocale() to dynamically load date formatting based on domain.

This wasn’t in the original specs, and honestly, I should’ve asked more questions during discovery. That said, the final system handles:

  • Arabic/Dhivehi/English mix for text
  • Dual calendar system (Gregorian + Hijri)
  • Right-to-left layouts via a per-tenant rtl boolean flag in config

Real-World Test Case: Tawasul Limo

This reminded me of a similar project: Tawasul Limo, a Laravel+Next.js limo booking platform. They didn’t use multi-tenancy, but we applied similar database isolation principles for VIP clients with compliance requirements (GDPR, UAE Data Law). It’s running on 23 servers across Middle East data centers now.

Main difference? Tawasul had 3 major variants; this platform serves 12 tenants with 95% code reuse.

Deployment Gotchas

Docker became my best friend. We built a base image for the core app, then a script that generated tenant-specific Dockerfiles with config overrides. Pushing updates meant rebuilding only the core layer, then restarting containers — total downtime: 2-4 seconds per tenant.

But here’s a weird local quirk: some government agencies in the UAE flag generic SSL certificates as “untrusted” on internal networks. We ended up buying Comodo certs branded under the client’s company name for 7 tenants.

What I’d Do Differently

Versioned deployments for each tenant would’ve saved time. When the first two clients hit production bugs, we had to roll back for everyone. Later we added tenant-aware version tags (v3-businessX-12-08-2025) using Laravel Envoy, which let us isolate fixes.

Also, don’t skimp on logging. We used Laravel Telescope per-tenant database connections to track which business triggered which job — worth it when debugging cross-tenant queue issues.


Building this system taught me that multi-tenancy isn’t just a technical challenge — it exposes messy client expectations. One Abu Dhabi tenant insisted their UI must use a specific gradient in the logo, which took 48 hours of back-and-forth about “brand consistency.”

If you’re staring at a multi-tenancy problem, hit me up on sarahprofile.com/contact — I’ll share the tenant package comparison spreadsheet I never published.

S

Sarah

Senior Full-Stack Developer & PMP-Certified Project Lead — Abu Dhabi, UAE

7+ years building web applications for UAE & GCC businesses. Specialising in Laravel, Next.js, and Arabic RTL development.

Work with Sarah