Filament heeft multi-tenancy ingebouwd: één regel ->tenant(Team::class) in je panel en elke resource wordt automatisch gescoped op de actieve tenant. Dat dekt single-database SaaS met teams of organisaties. Voor een eigen database per klant heb je een extra package nodig, zoals stancl/tenancy....
Filament heeft multi-tenancy ingebouwd: één regel ->tenant(Team::class) in je panel en elke resource wordt automatisch gescoped op de actieve tenant. Dat dekt single-database SaaS met teams of organisaties. Voor een eigen database per klant heb je een extra package nodig, zoals stancl/tenancy. Het echte werk zit in de plekken die Filament níét voor je scoped.
Wat is multi-tenancy in Filament precies?
Multi-tenancy in Filament betekent: één panel, meerdere klanten (tenants), en elke gebruiker ziet alleen de data van de tenant waarin hij werkt. De tenant zit in de URL, bijvoorbeeld /app/acme/orders, en Filament filtert alle resource-queries op die tenant.
Belangrijk detail uit de Filament-documentatie: de ingebouwde tenancy gaat uit van een many-to-many-relatie. Een gebruiker kan lid zijn van meerdere teams en daartussen wisselen. Denk aan een boekhouder die vijf administraties beheert, of een freelancer die voor drie bureaus werkt.
Hoort elke gebruiker bij precies één klant? Dan zegt Filament zelf dat je de tenancy-feature niet nodig hebt. Een Laravel global scope plus een observer die team_id vult, is dan simpeler.
Nieuw met Filament? Begin bij onze Filament-pagina.
Hoe zet je tenancy op in Filament v4 en v5?
Je hebt drie dingen nodig: een tenant-model, een relatie tussen gebruikers en tenants, en de HasTenants-interface op je User-model. De API is in v4 en v5 gelijk; v5 voegde alleen Livewire 4-support toe.
Concreet:
- Een tenant-model, bijvoorbeeld
TeamofOrganization. - Een pivot-tabel
team_useren eenteam_idop elk model dat bij een tenant hoort. - Op je panel:
->tenant(Team::class). - Op je User-model:
HasTenantsmet twee methodes.
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasTenants;
use Filament\Panel;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
class User extends Authenticatable implements FilamentUser, HasTenants
{
public function teams()
{
return $this->belongsToMany(Team::class);
}
public function getTenants(Panel $panel): Collection
{
return $this->teams;
}
public function canAccessTenant(Model $tenant): bool
{
return $this->teams()->whereKey($tenant)->exists();
}
public function canAccessPanel(Panel $panel): bool
{
return true;
}
}
canAccessTenant() is geen formaliteit. De documentatie is expliciet: zonder deze check kan een gebruiker de data van een andere tenant zien door simpelweg het tenant-ID in de URL te raden.
Daarna regelt Filament de rest voor resources. Lijst- en edit-queries worden gescoped. Nieuwe records krijgen via creating- en created-events automatisch de juiste tenant. De actieve tenant haal je overal op met Filament::getTenant().
Extra opties die je in een SaaS vrijwel altijd gebruikt:
slugAttribute: 'slug'voor nette URL's in plaats van ID's.->tenantDomain('{tenant:slug}.jouwapp.nl')voor subdomeinen per klant.HasDefaultTenantom een gebruiker direct in zijn laatste team te laten landen.->tenantRoutePrefix('team')als je/app/team/acmewilt.
Hoe werken tenant-registratie en het tenant-profiel?
Filament levert twee kant-en-klare pagina's: registratie van een nieuwe tenant en een profielpagina om die tenant te bewerken. Je extendt een basisklasse, definieert een formulier en registreert de pagina op je panel.
- Registratie: een klasse die
Filament\Pages\Tenancy\RegisterTenantextendt, geregistreerd met->tenantRegistration(RegisterTeam::class). InhandleRegistration()maak je het team aan en koppel je de gebruiker, bijvoorbeeld met$team->members()->attach(auth()->user()). - Profiel: een klasse die
Filament\Pages\Tenancy\EditTenantProfileextendt, geregistreerd met->tenantProfile(...).
Wat niemand je vertelt: registratie staat standaard open voor iedere ingelogde gebruiker. Wil je dat alleen betalende klanten of uitgenodigde gebruikers een organisatie kunnen aanmaken? Dan bouw je die check zelf. Hetzelfde geldt voor uitnodigingen, rollen binnen een team en het overdragen van eigenaarschap. Filament levert de haakjes, niet de complete onboarding-flow.
Hoe koppel je billing aan tenants?
Filament heeft een billing-hook per tenant. Er is een officiële koppeling met Laravel Spark via het package filament/spark-billing-provider, of je schrijft zelf een provider.
De relevante methodes:
->tenantBillingProvider(new SparkBillingProvider())koppelt Spark.->requiresTenantSubscription()blokkeert het hele panel zonder actief abonnement.isTenantSubscriptionRequired()op een losse resource of pagina maakt alleen dát onderdeel betaald.->tenantBillingRouteSlug()past de URL van de billing-pagina aan.
Laravel Spark is een betaald product. Gebruik je Mollie of Stripe direct? Dan implementeer je de interface Filament\Billing\Providers\Contracts\BillingProvider. Die vraagt om een route naar je billing-pagina en middleware die controleert of het abonnement actief is. Voor Nederlandse SaaS met iDEAL is dat vaak de logische route.
Single-database of multi-database tenancy?
Filament's ingebouwde tenancy is single-database: alle klanten in één database, gescheiden door een team_id-kolom. Wil je per klant een eigen database, dan combineer je Filament met stancl/tenancy (Tenancy for Laravel) of een plugin daarbovenop.
De afweging in één tabel:
| Criterium | Single-database (Filament ingebouwd) | Multi-database (stancl/tenancy) |
|---|---|---|
| Setup | Uren tot dagen | Dagen tot weken |
| Isolatie van data | Logisch, via team_id en scopes | Fysiek, aparte database per klant |
| Risico bij één vergeten scope | Datalek naar andere tenant | Beperkt tot die ene database |
| Migraties | Eén keer draaien | Per tenant draaien (100 klanten = 100 migraties) |
| Rapportage over alle klanten | Eén query | Aggregeren over databases |
| Backup/restore per klant | Lastig | Eenvoudig |
| Klant eist eigen database (compliance) | Niet mogelijk | Ja |
| Hostingkosten | Laag | Hoger, meer connecties en beheer |
De eerlijke versie: voor de meeste B2B-SaaS-producten met tientallen tot honderden klanten is single-database prima. Multi-database wordt interessant als klanten contractueel fysieke scheiding eisen, als je per klant data wilt kunnen exporteren of verwijderen, of als één grote klant de rest niet mag vertragen.
Twee praktische punten bij stancl/tenancy in combinatie met Filament:
- Livewire-requests. Filament draait op Livewire. De Livewire update-route en file-uploads moeten óók door de tenancy-middleware. De stancl-documentatie beschrijft hiervoor een aparte Livewire-integratie. Vergeet je dit, dan werkt de eerste pageload en falen daarna alle AJAX-acties.
- Versie. De publieke, stabiele lijn op Packagist is v3 (v3.10.1 op het moment van schrijven). Er bestaan Filament-plugins die de nieuwere v4 integreren, deels als betaald product. Check per plugin welke versie hij verwacht.
Meer over de architectuurkeuze zonder Filament-bril: multi-tenant SaaS bouwen in Laravel.
Welke security-valkuilen heeft Filament tenancy?
De grootste valkuil: Filament scoped alleen queries van tenant-aware resources. Alles daarbuiten is jouw verantwoordelijkheid. De documentatie zegt het zelf: bij een gedeeltelijke of foute implementatie kan data van de ene tenant bij een andere terechtkomen.
Waar het in de praktijk misgaat:
- Validatieregels.
uniqueenexistskijken standaard over de hele tabel. Een klant ziet dan "dit e-mailadres is al in gebruik" voor een adres bij een andere klant. Dat lekt informatie. Gebruik->scopedUnique()en->scopedExists(). - Modellen zonder resource. Een model dat je alleen via een Select, widget of custom pagina gebruikt, wordt niet automatisch gescoped. Voeg zelf een global scope toe via middleware.
- Widgets en custom pagina's. Een dashboard-widget met
Order::sum('total')telt de omzet van álle klanten op. Filter expliciet opFilament::getTenant(). withoutGlobalScopes(). Schakel je alle global scopes uit, dan verdwijnt de tenancy-scope ook. Haal alleen de specifieke scope weg die je bedoelt.- Code buiten het panel. Queue-jobs, console commands, API-routes en service providers draaien zonder actieve tenant. Geef de tenant expliciet mee aan je jobs.
- Tenant-middleware. Eigen middleware via
->tenantMiddleware()draait standaard alleen bij de eerste pageload, niet bij Livewire-requests daarna. ZetisPersistent: trueals het bij elke request moet gebeuren.
Daarnaast: tenancy is geen autorisatie. Een gebruiker binnen hetzelfde team mag niet automatisch alles. Policies blijven nodig. Een policy moet ook checken of het record bij de actieve tenant hoort, niet alleen of de gebruiker de juiste rol heeft. Voor rollen per team werkt Filament Shield, al vraagt team-scoping daar extra configuratie. Zie rollen en rechten met Filament Shield en onze Filament-beveiligingschecklist.
De rekenstap is simpel. Eén vergeten scope in een SaaS is geen bug. Het is een datalek met meldplicht onder de AVG. Schrijf daarom per resource een test die met twee tenants controleert dat tenant A niets van tenant B ziet.
Wanneer is Filament geschikt als SaaS-basis?
Filament is een sterke basis voor B2B-SaaS waarin gebruikers vooral data beheren: lijsten, formulieren, dashboards, workflows. Het is een zwakke basis als je product draait om een eigen, sterk gebrande consumenteninterface.
Beslismatrix:
| Situatie | Filament als basis? |
|---|---|
| B2B-tool: CRM, planning, orderbeheer, portaal | Ja, sweet spot |
| Interne tool die je later aan klanten verkoopt | Ja |
| Klantportaal per organisatie met eigen data | Ja |
| Consumentenapp met marketing-UX en veel animatie | Nee, eigen frontend |
| Mobile-first product | Nee, API + app |
| Per klant fysiek gescheiden data verplicht | Ja, mét stancl/tenancy en extra bouwtijd |
| Duizenden tenants met zware rapportages | Ja, maar plan database-architectuur vooraf |
Waarom het werkt: je bouwt een CRUD-resource in minuten in plaats van dagen. Tabellen, filters, bulk-acties, exports en notificaties zitten erin. Je tijd gaat naar je product, niet naar het zoveelste admin-scherm. Onze eigen backoffice draait op Filament, juist om die reden.
Waar je tegenaan loopt:
- Look-and-feel. Je kunt thema's en kleuren aanpassen, maar het blijft herkenbaar Filament. Voor B2B is dat zelden een probleem.
- Publieke pagina's. Marketing-site, pricing en signup-landingspagina bouw je los, in Blade, Inertia of een aparte frontend.
- Complexe permissies. Teams, rollen per team, uitnodigingen en eigenaarschap zijn maatwerk bovenop Filament.
Twijfel je tussen Filament en een eigen frontend voor een portaal? Onze pagina over klantportalen in Laravel gaat dieper op die keuze in.
Samengevat
- Filament heeft single-database multi-tenancy ingebouwd:
->tenant(),HasTenants, registratie, profiel en billing-hooks. - Hoort elke gebruiker bij één klant? Dan is een global scope simpeler dan Filament-tenancy.
- Implementeer altijd
canAccessTenant(); anders is je tenant-scheiding via de URL te omzeilen. - Filament scoped alleen resources. Validatie, widgets, modellen zonder resource, jobs en API's scope je zelf.
- Gebruik
scopedUnique()enscopedExists()in plaats van gewoneunique/exists. - Multi-database alleen als compliance, data-export per klant of isolatie het echt vereist. Reken op extra bouwtijd en Livewire-configuratie.
- Policies blijven nodig: tenancy bepaalt wélke data, policies wat iemand ermee mag.
- Test per resource met twee tenants. Dat is je goedkoopste verzekering tegen een datalek.
Veelgestelde vragen
Ondersteunt Filament multi-tenancy standaard?
Ja. Sinds v3 heeft Filament ingebouwde multi-tenancy, en in v4 en v5 werkt die met dezelfde API. Je registreert een tenant-model op je panel en implementeert HasTenants op je User-model. Het is single-database: alle tenants delen één database met een tenant-kolom.
Kan ik met Filament een database per klant gebruiken?
Niet met de ingebouwde tenancy alleen. Daarvoor combineer je Filament met stancl/tenancy of een Filament-plugin die dat package integreert. Let op dat de Livewire update-route en file-uploads ook door de tenancy-middleware moeten, anders werken acties na de eerste pageload niet.
Is Filament tenancy veilig genoeg voor een SaaS?
De ingebouwde scoping is betrouwbaar voor resources, maar dekt niet alles. Validatieregels, widgets, modellen zonder resource en code buiten het panel moet je zelf scopen. Filament zegt in de documentatie letterlijk dat het geen garanties geeft over de security van jouw applicatie. Tests met meerdere tenants zijn daarom verplichte kost.
Hoe regel ik abonnementen per tenant in Filament?
Via een billing provider. Er is een officiële koppeling met Laravel Spark, en met requiresTenantSubscription() blokkeer je het panel zonder actief abonnement. Gebruik je Mollie of Stripe direct, dan schrijf je een eigen provider die de BillingProvider-interface implementeert.
Wanneer heb ik Filament-tenancy níét nodig?
Als elke gebruiker bij precies één organisatie hoort en nooit hoeft te wisselen. Filament raadt dan zelf aan om een gewone Laravel global scope en observer te gebruiken. Dat is minder code en minder configuratie.
Is Filament geschikt voor een SaaS met een eigen frontend voor eindklanten?
Deels. Filament is sterk voor het beheergedeelte en voor B2B-portalen. Voor een consumentgerichte interface met eigen branding bouw je de frontend los, en gebruik je Filament voor je interne beheer of klantbeheer.
Een SaaS op Laravel en Filament bouwen en wil je de tenancy-architectuur vooraf laten checken? Neem contact op, dan kijken we mee.

Geschreven door Ruthger Idema
15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.
Meer over ons team →