Naar de inhoud
Ffantomu.dev
FNT / Blog · Nº 03← Alle artikelen

Een multi-tenant SaaS bouwen in Laravel: architectuurkeuzes die tellen

Een woontoren met rijen identieke ramen

Laravel · SaaS23 april 2026

Multi-tenancy is een van de weinige architectuurkeuzes in SaaS-ontwikkeling die achteraf echt moeilijk te veranderen is. Doe je het vroeg goed, dan wordt het onzichtbare infrastructuur. Doe je het fout, dan ben je maanden bezig met het refactoren van kernmodellen terwijl je probeert bestaande klanten niet te raken.

Dit is een gids voor de keuzes die er op dag een toe doen: de keuzes die alles beperken. En voor de keuzes die veilig kunnen wachten.


Keuze 1: databasestrategie

Er zijn drie standaardbenaderingen voor het isoleren van tenantgegevens, elk met een andere afweging tussen isolatie en operationele complexiteit.

Gedeelde database, gedeelde tabellen (rijgebaseerde tenancy)

Elke tabel heeft een tenant_id-vreemde sleutel. Alle tenants delen hetzelfde schema. Dit is de eenvoudigste aanpak om te implementeren en het gemakkelijkst te beheren: één database, één migratie-uitvoering, standaard Laravel-tooling door de hele stack.

Het risico is gegevenslekken. Een ontbrekende where tenant_id = ?-clausule in een query retourneert de gegevens van alle tenants. In Laravel beperk je dit met een globale scope op elk Eloquent-model, die automatisch het tenantfilter toevoegt. De scope moet worden geregistreerd voor er een query wordt uitgevoerd, doorgaans in middleware.

Gedeelde database, aparte schema's

Elke tenant krijgt zijn eigen databaseschema (in PostgreSQL) of databaseprefix (in MySQL). Migraties worden per tenant uitgevoerd. De applicatie wisselt het actieve schema bij elk verzoek. Dit biedt sterkere logische isolatie dan rijgebaseerde tenancy zonder de operationele overhead van aparte databaseservers.

Database per tenant

Elke tenant heeft een volledig aparte database. Dit biedt de sterkste isolatie en maakt het eenvoudig om de gegevens van een enkele tenant te migreren, te back-uppen of te verwijderen. De kosten zijn operationeel: migraties uitvoeren over honderden databases vereist tooling, en verbindingspooling wordt een zorgpunt op schaal.

Onze standaardaanbeveling voor vroeg-stadium SaaS is rijgebaseerde tenancy met een globale Eloquent-scope. Het is het snelst te bouwen, het gemakkelijkst te beheren en relatief eenvoudig weg te migreren als je later sterkere isolatie nodig hebt.


Keuze 2: tenantidentificatie

Je moet weten welke tenant een verzoek doet voordat er applicatielogica wordt uitgevoerd. De twee gangbare benaderingen zijn subdomeinroutering en padgebaseerde routering.

Subdomeinroutering (bedrijf.jouwapp.nl) is het meest gebruikte SaaS-patroon. Het vereist wildcard-DNS en een wildcard-SSL-certificaat, maar biedt schone URL-scheiding en maakt tenantcontext direct duidelijk. Verwerk de tenant in middleware die $request->getHost() leest, het subdomein verwijdert en de tenantrecord opzoekt.

Padgebaseerde routering (jouwapp.nl/bedrijf) is eenvoudiger in te stellen maar minder gangbaar voor SaaS. Het werkt goed voor interne tools of beheerpanelen waar aangepaste domeinen niet vereist zijn.

Welke aanpak je ook kiest: de tenantresolutie moet plaatsvinden in middleware en de opgeloste tenant moet worden gebonden in de service-container, zodat hij overal beschikbaar is zonder hem door elke methodeaanroep te hoeven doorgeven.


Keuze 3: wachtrij-isolatie

Wanneer een taak naar een wachtrij wordt gestuurd, is de HTTP-verzoekcontext (inclusief de opgeloste tenant) verdwenen. Als je taken tenantgegevens verwerken, moet je de tenantidentificator met de taak serialiseren en de tenant aan het begin van dehandle()-methode opnieuw oplossen.

Het schoonste patroon is een TenantAware-interface met bijbehorende taakmiddleware die de tenant-ID uit de taak leest, de tenant opzoekt en hem in de container registreert voor handle() wordt aangeroepen. Dit houdt de tenantresolutielogica op één plek in plaats van gedupliceerd over elke taakklasse.


Keuze 4: migraties

Bij rijgebaseerde tenancy zijn migraties eenvoudig: je voert ze eenmalig uit op de gedeelde database. Bij schema-per-tenant of database-per-tenant heb je een migratietool nodig die over tenantrecords itereert en openstaande migraties toepast op het schema of de database van elke tenant.

Bouw deze tooling voordat je meer dan een handvol tenants hebt. Migraties handmatig uitvoeren over 200 databases is geen houdbaar deploymentproces.


Wat kan wachten

Niet alles hoeft op dag een opgelost te worden. Facturatie-integratie (een Stripe-klant per tenant), per-tenant feature flags, tenantspecifieke configuratie en gebruiksmonitoring kunnen allemaal stapsgewijs worden toegevoegd zodra het kernislatiemodel werkt. Begin met de eenvoudigste aanpak die tenantgegevens correct scheidt en bouw vandaaruit verder.

Het doel in de beginfase is het onmogelijk maken van het per ongeluk doen van het verkeerde. Een globale scope die tenantfiltering op elke query afdwingt is daarvoor het juiste middel, niet het bouwen van infrastructuur voor een schaal die je nog niet hebt bereikt.

Laten we praten · มาคุยกัน

Klaar om jouw project te bespreken?