Building Multi-Tenancy in Laravel with React.js: A Complete Guide

Author

Kritim Yantra

Jun 09, 2025

Building Multi-Tenancy in Laravel with React.js: A Complete Guide

1. What is Multi-Tenancy?

Multi-tenancy allows a single application to serve multiple customers (tenants) while keeping their data isolated. Common approaches:

  • Database per Tenant (Most secure, complex)
  • Shared Database with Tenant ID (Easier, uses tenant_id column)
  • Schema per Tenant (PostgreSQL-only)

In this guide, we’ll use Shared Database with Tenant ID for simplicity.


2. Project Setup

2.1. Install Laravel & React

composer create-project laravel/laravel:^12.0 multi-tenant-app
cd multi-tenant-app
npm install react react-dom @vitejs/plugin-react

2.2. Configure Vite for React

Update vite.config.js:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    laravel(['resources/js/app.jsx']),
    react(),
  ],
});

2.3. Set Up Multi-Tenancy

We’ll use Laravel’s global scopes and middleware to isolate tenant data.


3. Backend: Multi-Tenancy in Laravel

3.1. Add tenant_id to Users & Tenant-Specific Models

php artisan make:migration add_tenant_id_to_users_table
// Migration
public function up() {
  Schema::table('users', function (Blueprint $table) {
    $table->foreignId('tenant_id')->constrained('tenants')->onDelete('cascade');
  });
}

3.2. Create a Tenant Model

php artisan make:model Tenant -m
// Migration
Schema::create('tenants', function (Blueprint $table) {
  $table->id();
  $table->string('name');
  $table->string('domain')->unique();
  $table->timestamps();
});

3.3. Set Up Global Tenant Scope

// app/Models/Tenant.php
use Illuminate\Database\Eloquent\Builder;

protected static function booted() {
  static::addGlobalScope('tenant', function (Builder $builder) {
    if (auth()->check()) {
      $builder->where('tenant_id', auth()->user()->tenant_id);
    }
  });
}

3.4. Create Tenant Middleware

php artisan make:middleware TenantMiddleware
// app/Http/Middleware/TenantMiddleware.php
public function handle($request, Closure $next) {
  if ($tenant = Tenant::where('domain', $request->getHost())->first()) {
    config(['tenant' => $tenant]);
    return $next($request);
  }
  abort(404, 'Tenant not found.');
}

Register in app/Http/Kernel.php:

protected $middlewareGroups = [
  'web' => [
    \App\Http\Middleware\TenantMiddleware::class,
  ],
];

3.5. Tenant-Aware Authentication

Modify LoginController to ensure users log in only to their tenant:

protected function attemptLogin(Request $request) {
  return Auth::attempt([
    'email' => $request->email,
    'password' => $request->password,
    'tenant_id' => Tenant::where('domain', $request->getHost())->first()->id,
  ]);
}

4. Frontend: React.js Multi-Tenant UI

4.1. Fetch Tenant-Specific Data

// resources/js/components/TenantDashboard.jsx
import { useEffect, useState } from 'react';
import axios from 'axios';

export default function TenantDashboard() {
  const [data, setData] = useState([]);

  useEffect(() => {
    axios.get('/api/tenant-data').then((res) => {
      setData(res.data);
    });
  }, []);

  return (
    <div>
      <h1>Tenant Dashboard</h1>
      {data.map((item) => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  );
}

4.2. Dynamic Tenant Routing

Use React Router to handle tenant-specific routes:

// resources/js/routes/AppRouter.jsx
import { Routes, Route } from 'react-router-dom';

export default function AppRouter() {
  return (
    <Routes>
      <Route path="/dashboard" element={<TenantDashboard />} />
      <Route path="/settings" element={<TenantSettings />} />
    </Routes>
  );
}

4.3. Tenant Switching (If Allowed)

// resources/js/components/TenantSwitcher.jsx
export default function TenantSwitcher() {
  const [tenants, setTenants] = useState([]);

  useEffect(() => {
    axios.get('/api/user/tenants').then((res) => {
      setTenants(res.data);
    });
  }, []);

  return (
    <select onChange={(e) => window.location.href = `https://${e.target.value}.yourdomain.com`}>
      {tenants.map((tenant) => (
        <option key={tenant.id} value={tenant.domain}>{tenant.name}</option>
      ))}
    </select>
  );
}

5. Testing Multi-Tenancy

  1. Create two tenants:
    Tenant::create(['name' => 'Tenant A', 'domain' => 'tenant-a.local']);
    Tenant::create(['name' => 'Tenant B', 'domain' => 'tenant-b.local']);
    
  2. Register users under each tenant.
  3. Verify data isolation:
    • Log in to tenant-a.local → Only see Tenant A’s data.
    • Log in to tenant-b.local → Only see Tenant B’s data.

6. Best Practices

Use Subdomains (tenant1.yourdomain.com) for easy routing.
Cache Tenant Data to avoid repeated DB queries.
Backup Tenant Databases Separately if using DB-per-tenant.
Use Queues for Tenant-Aware Jobs (Laravel’s Queue::tenant()).


7. Conclusion

You’ve built a multi-tenant SaaS app with:

  • Laravel (Backend tenant isolation)
  • React.js (Dynamic frontend per tenant)
  • Subdomain routing (For tenant separation)
LIVE MENTORSHIP ONLY 5 SPOTS

Laravel Mastery
Coaching Class Program

KritiMyantra

Transform from beginner to Laravel expert with our personalized Coaching Class starting June 20, 2025. Limited enrollment ensures focused attention.

Daily Sessions

1-hour personalized coaching

Real Projects

Build portfolio applications

Best Practices

Industry-standard techniques

Career Support

Interview prep & job guidance

Total Investment
$200
Duration
30 hours
1h/day

Enrollment Closes In

Days
Hours
Minutes
Seconds
Spots Available 5 of 10 remaining
Next cohort starts:
June 20, 2025

Join the Program

Complete your application to secure your spot

Application Submitted!

Thank you for your interest in our Laravel mentorship program. We'll contact you within 24 hours with next steps.

What happens next?

  • Confirmation email with program details
  • WhatsApp message from our team
  • Onboarding call to discuss your goals

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts

Understanding Laravel 12 Routes
Web Development
Understanding Laravel 12 Routes
Laravel Php
Kritim Yantra Kritim Yantra
Apr 15, 2025
What Is Model Context Protocol (MCP)?
Machine Learning
What Is Model Context Protocol (MCP)?
Python AI LLM
Kritim Yantra Kritim Yantra
Apr 21, 2025