Monorepo versus polyrepo voor- en nadelen vergeleken
Samenvatting
Monorepo versus polyrepo voor- en nadelen draaien om een meetbaar getal: het percentage features dat wijzigingen in meerdere services vereist. Faros AI benchmarkte 320 teams over 12 maanden: mediane PR-doorlooptijd 19 uur voor monorepo versus 2 uur voor polyrepo -- een factor 9,5. De 30%-drempel is richtinggevend: onder die grens profiteert polyrepo van isolatie, daarboven loont monorepo mits je platform-engineeringcapaciteit in de tooling investeert.
Het antwoord op monorepo versus polyrepo voor- en nadelen is geen aanbeveling -- het is een meting. Concreet: welk percentage van je features vereist wijzigingen in meer dan een service boundary?
Als je dat getal niet kent, neem je een infrastructuurbeslissing op basis van teamvoorkeur. In een engineeringorganisatie van 50 mensen kost die voorkeur iemand een zondag.
De kern is berekening. Beide aanpakken leggen kosten op. De vraag is welke kosten je organisatie beter kan absorberen: de coördinatietax van polyrepo, of de tooling-investering van monorepo.
PR-doorlooptijden zouden dit moeten beslissen -- maar dat doen ze niet
Faros AI analyseerde 320 engineeringteams over 12 maanden en stelde vast dat monorepo-omgevingen een mediane PR-doorlooptijd hebben van 19 uur. Polyrepo-omgevingen: 2 uur.
Dat is een factor 9,5 bij de mediaan. Bij het 90e percentiel loopt het verschil terug tot 8,6 dagen versus 5,5 dagen -- maar beide staarten zijn traag. Het gemiddelde convergeert ook: 3,6 dagen voor monorepo, 2,8 dagen voor polyrepo.
Het tegenargument is bekend: monorepos hebben snellere individuele build-tijden wanneer caching werkt. Een polyrepo-team dat een cross-service wijziging coördineert over vijf repositories -- elk met een eigen CI-pipeline en vijf afzonderlijke CODEOWNERS-goedkeuringen -- sluit die PR ook niet in twee uur.
De data vangt doorlooptijden voor typische PRs, niet voor worst-case cross-cutting changes. Dat onderscheid telt. Polyrepo-teams noemen hun mediaan (snel, want de meeste PRs zijn geïsoleerd). Monorepo-voorstanders wijzen op de pijn van cross-repo-coördinatie (ook reëel, en gedocumenteerd in hun worst-case PR-staarten). Beide kanten hebben gelijk over verschillende scenario's.
De data regelt het debat niet. Ze maakt de afweging preciezer dan onderbuikgevoel doet. Voor een team van 30 engineers met voornamelijk service-specifieke PRs is de 2-uur mediaan van polyrepo reëel. Voor een team van 80 dat elke sprint cross-cutting features shipt, is de 8,6-dagenstaart van monorepo ook reëel. Beide getallen zijn nuttig -- zolang je weet welke situatie op jou van toepassing is.

De blast radius die je niet berekent
Dit staat zelden op de slides van een conference talk: in een monorepo belandt een kapotte gedeelde dependency in elke service die haar importeert, in dezelfde commit, voordat iemand met downstream-eigenaarschap de wijziging heeft beoordeeld.
In een polyrepo breekt een kapotte packageversie de services die hem upgraden -- maar alleen wanneer ze upgraden. De blast radius wordt uitgesteld en begrensd door de keuze van de consumer.
Dat is relevant voor SLO-gated rollouts. Een slechte gedeelde library in een monorepo geeft je geen canary-venster. Het geeft je een cross-service blast radius in een enkel deploy-event. Je error budget begint over meerdere SLOs tegelijk weg te lopen voordat je rollout-automatisering het patroon detecteert en een revert activeert.
In een polyrepo is de rollout van een gedeelde dependency-wijziging van nature sequentieel. Service A upgradet en je observeert de SLO. Service B upgradet drie dagen later. De blast radius is op elk moment begrensd door wie de wijziging al heeft overgenomen.
De vraag is niet welke structuur inherent veiliger is -- het is wat je deployment-primitieve is. Als je deployment-eenheid de service is met een eigen SLO-gate, geeft polyrepo je natuurlijke isolatie. Als je deployment-eenheid de atomaire feature-wijziging is die consistent over frontend, API en background worker landt, geeft monorepo je die coördinatie zonder versioning-drift.
De meeste teams die microservices shippen hebben het eerste probleem. De meeste teams die een strak gekoppeld productoppervlak shippen, het tweede.
Waarom polyrepo-teams vastlopen bij 50 ingenieurs
De coördinatietax accumuleert. Bij 8 ingenieurs is het beheren van vier repositories vervelend maar haalbaar. Bij 50 wordt het een deeltijdse job voor meerdere mensen.
Concrete signalen dat de overhead van polyrepo-coördinatie structureel is geworden:
Je platform-team onderhoudt een shared-libraries-repo waarover niemand duidelijk eigenaarschap heeft
Versioning over services is genoeg gedivergeerd dat het bumpen van de gedeelde library een twee-weken project is
Een nieuwe ingenieur kan niet productief zijn zonder te begrijpen welke van je 23 repositories hij eerst moet clonen
Security patches voor gedeelde dependencies vereisen gecoördineerde PRs over een tiental repos, met een tracking-spreadsheet
Geen van deze zijn verzonnen pathologieën. Het zijn gedocumenteerde failure modes van teams die 80 ingenieurs bereikten en terugkeken op hun repo-beslissingen met spijt.
Polyrepo werkt wanneer teams echt onafhankelijk zijn: verschillende release-cycli, verschillende tech-stacks, verschillende on-call-rotaties. Wanneer teams genoeg code delen dat een wijziging in een service vereist dat je over drie anderen nadenkt, wordt de isolatie waarvoor polyrepo was gekozen het mechanisme dat coördinatie pijnlijk maakt.
De organisatorische indicator: tel het aantal Slack-kanalen dat specifiek bestaat om cross-repo-releases te coördineren. Als dat antwoord hoger is dan nul, betaal je de coördinatietax al consistent. De pijn is niet zichtbaar in één incident -- ze is gradueel. Ze accumuleert in kleine fricties: de platform-engineer die voor de derde keer uitleggen moet hoe je een gedeelde package bumpt zonder drie pipelines te breken. Op een gegeven moment stopt iemand met vragen en werkt rond het probleem. Dat moment is het echte beginpunt van technische schuld.
Wat monorepos werkelijk kosten bij het 95e percentiel
De P90-data van Faros AI is instructief: 8,6 dagen voor monorepo-PRs bij het 90e percentiel. Dat is geen traag team -- het is de structurele consequentie van grote cross-cutting changes die coördinatie vereisen over meerdere code-eigenaren, bredere CI-matrices en reviewcycli die organisatorische grenzen overschrijden.
Google heeft Bazel. Meta bouwde Buck. Nx Cloud en Turborepo remote cache bestaan omdat de tooling-investering om een monorepo goed te laten functioneren niet triviaal is. Een monorepo bij 200 ingenieurs zonder affected-only build-selectie, distributed caching en geautomatiseerde merge-queues levert CI-runs van 45 minuten op voor PRs die een gedeelde utility-functie raken.
De tooling-kosten zijn reëel en worden stelselmatig onderschat. Teams die monorepos succesvol op schaal opereren, hebben doorgaans platform-engineers aangenomen die specifiek op die infrastructuur focussen. Monorepo-tooling retroflitten op een groeiende codebase terwijl je ook product shipt, vreet aan je deployment-frequentie voordat het in een post-mortem verschijnt.
Als je platform-team al overstretched is, is monorepo-tooling-onderhoud toevoegen een wezenlijke commitment -- geen configuratiekeuze.

De 30%-regel die goed presterende teams gebruiken
Een bruikbare heuristiek van teams die deze beslissing bewust hebben genomen: als meer dan 30% van je features wijzigingen in meerdere service boundaries vereist, zal de coördinatie-overhead van een polyrepo uiteindelijk de tooling-investering van een goed gerunde monorepo overschrijden.
Onder 30% -- waar de meeste microservices-organisaties zitten -- wegen de isolatievoordelen van polyrepo doorgaans op tegen de coördinatietax. Cross-service wijzigingen gebeuren, maar niet frequent genoeg om gedeelde tooling sneller te laten renderen dan isolatie doet.
Dit is meetbaar. Trek de laatste zes maanden aan samengevoegde PRs en tel hoeveel wijzigingen in meer dan een repository vereisten om een enkele gebruikersgerichte feature te shippen. Dat ratio is je input. Het is niet precies tot op een decimaal, maar het is richtinggevend -- en richtinggevend is genoeg om het debat te stoppen dat op teamvoorkeur draait.
Een team met een cross-service-ratio van 12% heeft geen monorepo nodig. Een team op 38% en groeiend betaalt een coördinatietax die blijft accumuleren. De meting zelf kost minder dan een Sprint: één query op je git-log, een pivot-tabel, en je hebt een beslissingsonderbouwing die geen architectuuroverleg meer nodig heeft. Dat getal -- niet de voorkeur van de tech lead -- is de input die telt.
Hoe je rollout-strategie de berekening verandert
Er is een dimensie van deze beslissing die bijna geen aandacht krijgt: je rollout-primitieve.
Als je percentage-based rollouts uitvoert met SLO-gates -- een feature naar 5% van het verkeer shippen, error budgets bewaken, dan progressief uitbreiden -- verandert je blast-radius-berekening afhankelijk van of de feature een of meerdere services omvat.
In een polyrepo vereist een multi-service feature rollout het coördineren van de rollout-staat over services. Service A kan op 20% staan terwijl Service B nog op 0% staat, wat inconsistente toestanden creëert die genuinely moeilijk te doorgronden zijn onder incidentomstandigheden. Feature flags helpen, maar je beheert nog steeds cross-service vlagstatus zonder een enkele bron van waarheid voor rollout-voortgang.
In een monorepo met atomaire commits landt de feature consistent over services. De rollout kan nog steeds percentage-based zijn op infrastructuurniveau, maar de code is consistent vanaf het moment van de deploy. Je SLO-gates activeren op een coherente toestand.
Teams die veel atomaire multi-service features doen en progressieve rollouts uitvoeren met geautomatiseerde rollback op SLO-schending, merken vaak dat de consistentie van monorepo een hele categorie incidenten elimineert die polyrepo geen schone naam voor heeft -- het cross-service state divergence-incident dat eruitziet als een bug maar eigenlijk een deployment-coördinatieprobleem is.
Wat het post-mortem werkelijk zal zeggen
De meeste engineeringorganisaties eindigen op een hybride die niemand hybride noemt, omdat het klinkt als een architecturale compromisbeslissing.
Een of twee monorepos voor strak gekoppelde productoppervlakken. Aparte repositories voor echt autonome services met onafhankelijke deployment-cycli, eigen on-call-rotatie en een team dat de afgelopen zes maanden geen gedeelde library-wijziging hoefde te coördineren.
Het signaal om je huidige setup te heroverwegen:
De frequentie van cross-service wijzigingen heeft 30% overschreden en CI-runtimes accumuleren
Je hebt platform-engineers aangenomen met capaciteit om in monorepo-tooling te investeren
Een blast-radius-incident onthulde dat je polyrepo-isolatie nep was -- de services deelden genoeg infrastructuur dat de isolatie comfort bood, geen veiligheid
Het signaal dat de beslissing nu goed is:
Teams zijn echt onafhankelijk en coördinatie-overhead is laag
Je ergste incident werd niet veroorzaakt door cross-service dependency-drift
Platform-engineeringcapaciteit bestaat niet om monorepo-tooling te onderhouden zonder productlevering te vertragen
Het post-mortem zal je vertellen in welke van deze je werkelijk leeft. Dat document is meestal eerlijker dan de architecture decision record die voorafging aan het systeem dat het beschrijft.