The SaaS Scaling Challenge
When building B2B SaaS applications, you inevitably hit the "Tenancy" crossroad. You have hundreds of companies using your platform, and you must ensure that Company A never accidentally sees Company B's data. You could deploy a separate database for every client, but managing 500 databases quickly becomes an infrastructure nightmare.
At Smart Tech Devs, we prefer the Single-Database Multi-Tenancy approach. It allows us to keep infrastructure costs low while ensuring absolute data isolation at the application level.
Data Isolation via Global Scopes
The biggest risk in a single-database architecture is a developer forgetting to add a where('tenant_id', $id) clause to an Eloquent query. To solve this, we remove the human element entirely using Laravel's Global Scopes.
Step 1: The Tenant Scope
We define a Global Scope that automatically appends a tenant filter to every query executed on a model.
namespace App\Models\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
class TenantScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
// Automatically scope queries to the currently authenticated user's tenant
if (Auth::hasUser() && Auth::user()->tenant_id) {
$builder->where('tenant_id', Auth::user()->tenant_id);
}
}
}
Step 2: Applying the Trait
Instead of manually adding this scope to every model, we create a reusable trait. Any model (e.g., Invoices, Employees, Projects) that belongs to a tenant simply uses this trait.
namespace App\Traits;
use App\Models\Scopes\TenantScope;
trait BelongsToTenant
{
protected static function bootBelongsToTenant()
{
static::addGlobalScope(new TenantScope);
// Automatically assign the tenant_id when creating a new record
static::creating(function ($model) {
if (session()->has('tenant_id')) {
$model->tenant_id = session()->get('tenant_id');
}
});
}
}
The Engineering ROI
By enforcing tenancy at the ORM level, developers can write simple queries like Invoice::all() without worrying about cross-client data leaks. Laravel automatically handles the filtering behind the scenes. This architecture allows you to scale a SaaS to thousands of tenants on a single, easily maintainable database while maintaining enterprise-grade data security.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.