Tek bir Laravel uygulamasının, birden fazla müşteriyi (tenant) aynı anda izole şekilde yönetmesini ister misiniz?
Modern SaaS (Software as a Service) projelerinin kalbinde yer alan multi-tenancy (çok kiracılı mimari) tam olarak bunu sağlar.
Bu yazıda:
-
Multi-tenancy mimarisinin mantığı
-
Laravel’de hangi senaryolarda nasıl kurulur
-
Sıfırdan kendi yapınızı geliştirmek
-
Veya hazır bir çözüm: stancl/tenancy paketi kullanmak
-
Performans ve güvenlik ipuçları
hepsini adım adım, bol örnekle ve uygulamalı kod parçalarıyla bulacaksınız.
Multi-Tenancy Nedir?
Multi-Tenancy, bir uygulamanın altyapısının birden çok müşteri (tenant) tarafından paylaşılmasıdır.
Her tenant:
✅ Aynı kod tabanını kullanır
✅ Verileri diğer tenant’lardan tamamen ayrıdır
✅ Kendi özel yapılandırmasına sahip olabilir
Örneğin: Shopify, Slack, Notion… Bunlar hepsi SaaS’ta çok kiracılı yapı kullanır.
Multi-Tenancy Mimarisi: Hangi Tipleri Var?
Laravel ile SaaS geliştirmek isteyenlerin önce hangi yapıyı seçeceğine karar vermesi gerekir.
1) Shared Database - Shared Schema
-
Tüm tenant’lar aynı veritabanını ve tabloları paylaşır
-
Tablo satırlarında
tenant_idalanı bulunur -
Basit yönetim, düşük maliyet
-
Büyük ölçeklerde query optimizasyonu kritik
2) Separate Database
-
Her tenant’ın kendi veritabanı vardır
-
Veriler birbirinden tamamen ayrıdır
-
Güvenlik ve veri gizliliği üst düzeydedir
-
Daha karmaşık bir bağlantı yönetimi gerekir
3) Separate Schema (Alternatif)
-
Aynı veritabanı içinde her tenant için farklı şema (PostgreSQL’de yaygın)
-
Orta ölçekli SaaS projelerinde ideal olabilir
Laravel’de Sıfırdan Multi-Tenancy Nasıl Kurulur?
Burada Shared Database yapısını temel alarak ilerleyeceğiz.
En temel haliyle: tenants tablosu + tenant_id scoping.
Adım 1: Tenant Modeli ve Migration
Önce tenant’ları saklayacak temel bir tablo oluşturalım.
php artisan make:model Tenant -m
// database/migrations/xxxx_xx_xx_create_tenants_table.php
Schema::create('tenants', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('domain')->unique();
$table->timestamps();
});
Adım 2: Tenant Tespiti için Middleware
Her istek geldiğinde hangi tenant’a ait olduğunu bulmak için bir middleware kullanılır.
Burada örnek olarak domain bazlı tespit yapıyoruz.
php artisan make:middleware IdentifyTenant
// app/Http/Middleware/IdentifyTenant.php
namespace App\Http\Middleware;
use App\Models\Tenant;
use Closure;
use Illuminate\Support\Facades\App;
class IdentifyTenant
{
public function handle($request, Closure $next)
{
$host = $request->getHost();
$tenant = Tenant::where('domain', $host)->first();
if (!$tenant) {
abort(404, 'Tenant not found.');
}
App::instance('currentTenant', $tenant);
return $next($request);
}
}
Kernel’e ekle:
protected $middleware = [
\App\Http\Middleware\IdentifyTenant::class,
];
Adım 3: Tenant Bazlı Veri İzolasyonu
Örneğin posts tablosu tenant bazlı olsun.
Her Post kaydı mutlaka tenant_id ile işaretlenmeli.
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected static function booted()
{
static::addGlobalScope('tenant_id', function (Builder $builder) {
$tenant = app('currentTenant');
$builder->where('tenant_id', $tenant->id);
});
static::creating(function ($model) {
$model->tenant_id = app('currentTenant')->id;
});
}
}
Bu sayede:
Post::all(); // Sadece o tenant’a ait kayıtlar gelir
Adım 4: Ayrı Veritabanı Kullanmak İsterseniz
Separate Database senaryosunda middleware içinde dinamik bağlantı değiştirmek gerekir.
// IdentifyTenant Middleware içinde
config([
'database.connections.tenant' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => 'tenant_' . $tenant->id,
'username' => 'root',
'password' => '',
],
]);
DB::setDefaultConnection('tenant');
Model’de protected $connection = 'tenant'; şeklinde ayarlayarak ilgili veritabanına geçebilirsiniz.
Alternatif Yol: Tenancy for Laravel Paketi
Laravel topluluğunda stancl/tenancy en popüler çözümdür.
Özellikleri:
✅ Domain veya subdomain bazlı tenant yönetimi
✅ Separate database desteği
✅ Tenant başına migration & seed desteği
✅ Cache, queue, storage izolasyonu
Kurulum:
composer require stancl/tenancy
php artisan tenancy:install
php artisan migrate
Tenant başlatmak:
tenancy()->initialize($tenant);
Tenant migration:
php artisan tenancy:migrate
Ve alt alan adı bazlı örnek:
Route::domain('{account}.yoursaas.com')->group(function () {
Route::get('/', function ($account) {
tenancy()->initialize($account);
return view('dashboard');
});
});
Güvenlik & Performans İpuçları
✅ Her tenant için storage, cache, queue gibi bileşenleri izole et.
✅ Büyük veri hacminde read replica, partitioning gibi çözümler kullan.
✅ Verileri tenant_id bazlı scoping ile her sorguda filtrele.
✅ API token veya session yönetiminde tenant doğrulamasını unutma.
✅ Subdomain veya domain bazlı yapı SEO açısından da önemlidir.
Kimler İçin İdeal?
-
Birden fazla müşteri için tek bir Laravel uygulaması çalıştırmak isteyen girişimler.
-
SaaS iş modeli kurmak isteyen startup’lar.
-
Düşük bakım maliyetiyle ölçeklenebilir sistem tasarlamak isteyen ekipler.
Sonuç
✔ Multi-tenancy, SaaS dünyasında olmazsa olmazdır.
✔ Laravel, hem paket desteği hem framework esnekliği ile çok güçlüdür.
✔ İster sıfırdan kur, ister Tenancy for Laravel gibi bir paket kullan, önemli olan: veri izolasyonu ve güvenliği doğru planlamak.
