Database sharding in Laravel: wanneer is het echt nodig en hoe pak je het aan? Leer het verschil met read replicas, tenant-based sharding, connection management en de valkuilen.
Database sharding met Laravel — wanneer en hoe
95% van de Laravel-applicaties heeft nooit database sharding nodig. Toch is het een van de meest besproken schaalbaarheidsstrategieën. Dit artikel legt uit wanneer je wél aan sharding toe bent, hoe je het aanpakt in Laravel, en — misschien belangrijker — wat je eerst moet doen voordat je eraan begint.
Wij zien bij klanten dat query-optimalisatie, indexen en caching in de meeste gevallen het probleem oplossen. Sharding is een zwaar middel met hoge implementatiekosten. Gebruik het alleen als je de alternatieven hebt uitgeput. Dit artikel helpt je die afweging concreet te maken.
Eerst: wat is database sharding precies?
Sharding is het horizontaal verdelen van je database over meerdere servers. Elke server — een shard — bevat een subset van de data. Een webshop met 10 miljoen klanten kan die data bijvoorbeeld verdelen over vier shards: shard A bevat klanten 1–2,5 miljoen, shard B klanten 2,5–5 miljoen, enzovoort.
Het verschil met een read replica is fundamenteel. Een read replica kopieert álle data naar een tweede server voor leesverkeer. Sharding splitst de data zelf op. Beide technieken schalen, maar voor totaal verschillende problemen.
Read replica vs. sharding — wanneer gebruik je wat?
| Situatie | Read replica | Sharding |
|---|---|---|
| Veel leesverkeer, weinig schrijfverkeer | Ja | Nee |
| Schrijfverkeer groeit explosief | Nee | Ja |
| Dataset past op één server | Ja | Nee |
| Dataset overschrijdt servercapaciteit | Nee | Ja |
| Multi-tenant SaaS met data-isolatie | Deels | Ja |
| Implementatiecomplexiteit | Laag | Hoog |
In de praktijk is een read replica de juiste eerste stap. Laravel ondersteunt dit natively via de read en write configuratie in config/database.php. Je hoeft er geen regel code voor aan te passen — het framework routeert SELECT-queries automatisch naar de replica en schrijfoperaties naar de primaire server. Sharding vereist maatwerk of een externe package en vraagt aanpassingen door je hele codebase.
Wanneer is sharding wél nodig?
Drie concrete scenario's rechtvaardigen sharding:
1. Je schrijfvolume overbelast één server. Een primaire database kan doorgaans 5.000–20.000 writes per seconde verwerken, afhankelijk van hardware en query-complexiteit. Bij een grote B2C-webshop met veel gelijktijdige bestellingen, voorraadmutaties en event-logging kom je daar eerder dan verwacht aan. Zeker als je ook realtime voorraadupdates, feed-verwerking en logging op dezelfde server draait. 2. Je dataset past niet meer op één machine. Bij terabytes aan orderhistorie, productfeeds of logdata loop je tegen opslag- en memory-limieten aan. Indexen passen niet meer in RAM; query-performance daalt drastisch. Je merkt dit doordat queries die vroeger 10 ms duurden opeens 200–500 ms kosten — niet omdat de query slechter is geworden, maar omdat de buffer pool de data niet meer kwijt kan. 3. Je hebt data-isolatievereisten per tenant. Bij een multi-tenant SaaS-platform wil je soms dat klantdata fysiek gescheiden is — vanwege compliance (AVG/GDPR), contractuele eisen of performance-garanties per klant. Een trage tenant mag de performance van andere tenants niet beïnvloeden. Database sharding per tenant lost dat op.Optimaliseer eerst — serieus
Voordat je aan sharding begint, doorloop je deze checklist:
- Heb je slow query logging aanstaan? Analyseer de top 10 traagste queries.
- Zijn alle foreign keys geïndexeerd? Laravel maakt ze niet automatisch aan.
- Gebruik je
eager loading(with()) om N+1-problemen te voorkomen? - Zit je cache-laag correct? Redis of Memcached voor sessies, resultaten en feeds.
- Overweeg je read replicas voor leesintensieve routes?
- Is je database-server sized voor je workload? Een upgrade van 4 naar 16 GB RAM lost verrassend veel op.
Wij zien bij klanten dat een combinatie van query-optimalisatie en een read replica het probleem in 8 van de 10 gevallen oplost. De kosten zijn een fractie van een sharding-implementatie. Een senior developer lost een indexeringsprobleem op in een middag; een sharding-traject duurt maanden.
Tenant-based sharding in Laravel
De meest voorkomende sharding-strategie in Laravel-applicaties is tenant-based sharding. Elke tenant (klant, winkel, organisatie) krijgt een eigen database. Laravel heeft hier uitstekende native ondersteuning voor via config/database.php en de DB::reconnect() methode.
Database-configuratie
// config/database.php
'connections' => [
'tenant_a' => [
'driver' => 'mysql',
'host' => env('DB_HOST_TENANT_A', '10.0.0.2'),
'database' => 'tenant_a_db',
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'charset' => 'utf8mb4',
'collation'=> 'utf8mb4_unicode_ci',
],
'tenant_b' => [
'driver' => 'mysql',
'host' => env('DB_HOST_TENANT_B', '10.0.0.3'),
'database' => 'tenant_b_db',
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'charset' => 'utf8mb4',
'collation'=> 'utf8mb4_unicode_ci',
],
],
In de praktijk genereer je deze configuraties dynamisch, niet handmatig. Je beheert een centrale orchestration database met tenant-metadata — welke shard, welk host, welke database-naam.
Dynamische connection switching
// app/Services/TenantConnectionService.php
namespace App\Services;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
class TenantConnectionService
{
public function connectForTenant(Tenant $tenant): void
{
$shard = $tenant->shard; // bijv. object met host, database, etc.
Config::set("database.connections.tenant_{$tenant->id}", [
'driver' => 'mysql',
'host' => $shard->host,
'database' => $shard->database,
'username' => $shard->username,
'password' => $shard->password,
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
]);
DB::purge("tenant_{$tenant->id}");
DB::reconnect("tenant_{$tenant->id}");
DB::setDefaultConnection("tenant_{$tenant->id}");
}
}
Gebruik dit via een middleware die de tenant bepaalt op basis van het subdomein, een header of een JWT-claim. Zo is elke request automatisch verbonden met de juiste shard.
Middleware voorbeeld
// app/Http/Middleware/SetTenantConnection.php
public function handle(Request $request, Closure $next): Response
{
$tenant = Tenant::where('domain', $request->getHost())->firstOrFail();
app(TenantConnectionService::class)->connectForTenant($tenant);
return $next($request);
}
Horizontale sharding op basis van een shard key
Bij sharding op basis van een shard key (bijv. user_id of order_id) verdeel je records over shards via een hash of range. Dit is complexer dan tenant-based sharding, maar biedt meer flexibiliteit.
// Bepaal shard op basis van user_id (modulo-strategie)
function getShardConnection(int $userId, int $totalShards = 4): string
{
$shardIndex = $userId % $totalShards;
return "shard_{$shardIndex}";
}
// Gebruik:
$connection = getShardConnection($user->id);
$orders = DB::connection($connection)
->table('orders')
->where('user_id', $user->id)
->get();
De modulo-strategie is simpel maar inflexibel: als je van 4 naar 5 shards gaat, verandert de shard-toewijzing voor het merendeel van je records. Je moet data herindelen — een kostbare operatie op productie. Een consistente hash-ring (consistent hashing) minimaliseert dit probleem: bij het toevoegen van een shard verschuift slechts een klein deel van de data. De implementatie is complexer, maar voor systemen die moeten doorgroeien is het de juiste keuze.
Connection management — de valkuilen
Sharding introduceert complexiteit rondom connections. Dit zijn de meest voorkomende problemen die wij tegenkomen:
Connection pool exhaustion. Elke shard heeft een eigen connection pool. Bij 10 shards en 100 applicatieprocessen heb je snel 1.000 open database-connections. MySQL's standaardmax_connections is 151. Reken op ProxySQL of PgBouncer als connection pooler.
Cross-shard queries zijn niet mogelijk. Je kunt geen JOIN maken over twee shards. Data die samen moet leven (bijv. bestellingen + klanten), moet in dezelfde shard staan. Dit vereist zorgvuldig datamodel-ontwerp voordat je begint.
Transacties werken niet over shards heen. Distributed transactions (XA) bestaan, maar zijn traag en complex. Vermijd cross-shard writes waar mogelijk.
Schema-migraties worden lastiger. Een php artisan migrate werkt standaard op de default connection. Voor sharding moet je migraties uitvoeren per shard — en dit synchroon houden over tientallen databases is foutgevoelig. Tools zoals tenancy/tenancy bieden hier hulp met tenant-aware migratie-commands, maar je blijft afhankelijk van een goed deployment-proces.
Debuggen kost meer tijd. Query logs, Telescope en Debugbar tonen data per connection. Bij een bug op shard 3 moet je weten dat je op shard 3 moet kijken.
Packages die helpen
Je hoeft sharding niet volledig zelf te bouwen. Een aantal packages verdient aandacht:
tenancy/tenancy (stancl/tenancy) — de standaard voor multi-tenant Laravel. Ondersteunt database-per-tenant, automatische migraties, en tenant-aware queues. Aanbevolen als je multi-tenant SaaS bouwt. spatie/laravel-multitenancy — lichter alternatief van Spatie. Minder opinionated, meer flexibel. Geschikt als je eigen infrastructuur hebt en liever niet afhankelijk bent van een groot framework.Voor complexere sharding op basis van shard keys is er minder kant-en-klaar beschikbaar. Dat bouw je grotendeels zelf, op basis van de connection-switching techniek hierboven. Overweeg of de investering in een custom implementatie opweegt tegen de alternatieven — een managed database zoals PlanetScale (MySQL-compatibel) of Amazon Aurora heeft ingebouwde horizontale schaalbaarheid zonder dat je applicatiecode hoeft aan te passen.
Kosten en complexiteit — wees eerlijk
Sharding is niet gratis. Reken op de volgende impactgebieden:
| Impactgebied | Geschatte extra inspanning |
|---|---|
| Initiële implementatie | 3–8 weken voor een senior developer |
| Migratiestrategie bestaande data | 1–4 weken afhankelijk van datavolume |
| Aanpassingen aan queries en modellen | 1–3 weken |
| Monitoring en alerting opzetten | 1 week |
| Documentatie en kennisoverdracht | Doorlopend |
Dit zijn conservatieve schattingen voor een greenfield implementatie. Bij een bestaande applicatie met tientallen modellen en queries loop je al snel op meer aan.
Alternatieven die je eerst moet overwegen: verticale scaling (grotere server), columnar databases (ClickHouse, BigQuery) voor analytics-workloads, of data-archivering om je actieve dataset klein te houden.
Wanneer is sharding een goede keuze voor een Laravel-project?
Concreet: als je met een multi-tenant Laravel platform werkt waarbij klanten data-isolatie eisen, of als je aantoonbaar tegen schrijflimieten aanloopt na optimalisatie. In beide gevallen betaalt de investering zich terug in schaalbaarheid en klanttevredenheid.
Voor een e-commerce platform dat op Magento of Shopify draait, is database sharding vrijwel nooit nodig — die platformen hebben eigen schaalbaarheidsstrategieën.
Heb je een Laravel-applicatie die tegen performance-problemen aanloopt? Wij kijken eerst naar de quick wins voordat we zwaar geschut inzetten. Neem contact op voor een eerlijk technisch advies.
Veelgestelde vragen
Wat is het verschil tussen database sharding en een read replica?Een read replica kopieert alle data naar een extra server voor leesverkeer. Sharding verdeelt de data zelf over meerdere servers. Read replicas helpen bij leesintensieve workloads; sharding helpt als je schrijfvolume of datavolume te groot is voor één server.
Ondersteunt Laravel sharding natively?Laravel heeft geen ingebouwde sharding-ondersteuning, maar biedt wel flexibele multi-connection configuratie via config/database.php. Je kunt dynamisch wisselen van connection, wat de basis vormt voor elke sharding-strategie. Packages zoals stancl/tenancy bouwen hierop voort voor multi-tenant use cases.
Als je primaire database consistent boven de 70–80% CPU- of I/O-belasting zit ondanks query-optimalisatie en indexen, en een read replica het probleem niet oplost. Of als je dataset de beschikbare RAM van je server significant overschrijdt, waardoor indexen niet meer in memory passen.
Kan ik sharding combineren met Eloquent ORM?Ja. Eloquent ondersteunt het opgeven van een connection per model via de $connection property. Bij dynamische sharding stel je de default connection in via DB::setDefaultConnection() of je gebruikt ->on('shard_x') bij queries. Veel standaard Eloquent-functionaliteit werkt, maar relaties over shards heen werken niet zonder maatwerk.

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