DevOps 25. Juli 2026 9 Min. Lesezeit

CI/CD für Monorepos: Struktur, Caching, Pipeline-Performance

Monorepos können Releases vereinfachen, aber CI/CD schnell ausbremsen. Entscheidend sind klare Grenzen, gezielte Jobs und Caches, denen man vertrauen kann.

Emre Hayta
Emre Hayta
TECHZ

Warum Monorepos CI/CD anders belasten

Ein Monorepo ist nicht automatisch ein Problem. Im Gegenteil: Für Teams mit mehreren Services, Libraries, Frontends und gemeinsamen Standards kann ein gemeinsames Repository sehr angenehm sein. Abhängigkeiten sind sichtbar, Querschnittsänderungen lassen sich in einem Pull Request prüfen und Versionen driften weniger stark auseinander. Die Schwierigkeit beginnt meistens erst in der Pipeline. Wenn jede Änderung alle Tests, Builds und Deployments startet, wird aus einem gut gemeinten Setup schnell ein Bremsklotz.

Bei klassisch getrennten Repositories ist der Scope oft durch die Repo-Grenze vorgegeben. Im Monorepo muss die CI diese Grenze selbst kennen. Sie muss beantworten können, welche Pakete betroffen sind, welche Jobs wirklich nötig sind und wann ein vollständiger Lauf bewusst erzwungen wird. Ohne diese Logik bezahlt jedes Team bei jeder kleinen Änderung den Preis der gesamten Codebasis.

Struktur entscheidet vor dem ersten Cache

Bevor man Caching optimiert, sollte die Repository-Struktur stimmen. Eine gute Monorepo-Struktur macht Besitz, Abhängigkeiten und Build-Grenzen erkennbar. Typisch sind Verzeichnisse wie apps/, services/, packages/ oder libs/. Noch wichtiger als die Namen ist, dass sie konsequent verwendet werden. Wenn ein Backend-Service quer in Frontend-Pakete schreibt oder interne Libraries ohne klare API genutzt werden, kann keine Pipeline zuverlässig berechnen, was betroffen ist.

Praktisch hilft eine einfache Regel: Jedes deploybare Artefakt bekommt einen klaren Ordner, eine eigene Test- und Build-Definition und eine dokumentierte Liste direkter Abhängigkeiten. Gemeinsame Pakete sollten ebenfalls versionierbare Einheiten sein, auch wenn sie nicht separat veröffentlicht werden. Tools wie Nx, Turborepo, Bazel, Pants oder Gradle können diese Graphen auswerten, aber sie ersetzen keine saubere Modellierung.

apps/
  web-shop/
  admin-portal/
services/
  billing-api/
  notification-worker/
packages/
  ui/
  auth-client/
  eslint-config/

Affected Builds statt alles immer

Der größte Hebel für Pipeline-Performance ist selten ein einzelner schnellerer Test, sondern die Frage, ob der Test überhaupt laufen muss. Moderne Monorepo-Setups arbeiten deshalb mit "affected" Logik. Eine Änderung in packages/ui betrifft vielleicht beide Frontends, aber nicht den Billing-Service. Eine Änderung an einer Dockerfile-Vorlage oder an globalen CI-Skripten kann dagegen sehr wohl einen vollständigen Lauf rechtfertigen.

Wichtig ist, die Erkennung konservativ zu bauen. Falsch negative Ergebnisse sind gefährlicher als zu viele Jobs. Wenn die Pipeline einen betroffenen Service übersieht, landet ungeprüfter Code im Release. Deshalb sollten globale Dateien wie Lockfiles, zentrale Build-Konfiguration, Security-Policies und Shared-Test-Utilities explizit als breiter Trigger definiert werden. Lieber einmal zu viel testen als einen Produktionsfehler durch eine aggressive Abkürzung riskieren.

Caching richtig einsetzen

Caches sind in Monorepos unverzichtbar, aber sie sind kein Ersatz für saubere Jobs. Ein guter Cache ist reproduzierbar, eindeutig adressiert und leicht zu invalidieren. Ein schlechter Cache spart scheinbar Zeit, bis er alte Artefakte ausliefert und Fehler nur lokal oder erst nach dem Deployment sichtbar werden.

Bewährt hat sich eine Trennung mehrerer Cache-Ebenen. Dependency-Caches beschleunigen die Installation von Paketen. Build-Caches speichern Ergebnisse aus deterministischen Tasks. Docker-Layer-Caches helfen bei Images, wenn Basis-Layer und Package-Installation stabil bleiben. Test-Caches sollten besonders vorsichtig eingesetzt werden, weil Tests oft stärker von Umgebung, Zeit, Datenbankzustand oder Feature Flags abhängen.

Cache Keys sollten mindestens Betriebssystem, Laufzeitversion, Paketmanager, Lockfile und relevante Konfigurationsdateien berücksichtigen. Bei Node.js-Projekten reicht ein Key auf Basis von package-lock.json, pnpm-lock.yaml oder yarn.lock oft für Dependencies. Für Build-Ergebnisse braucht es zusätzlich Inputs des jeweiligen Projekts und seiner Abhängigkeiten. Genau hier zahlen sich Monorepo-Tools aus, weil sie Hashes nicht nur aus einem Ordner, sondern aus dem tatsächlichen Abhängigkeitsgraphen bilden können.

Pipeline-Design für schnelles Feedback

Eine gute CI/CD-Pipeline ist nicht nur schnell, sondern gibt früh das richtige Feedback. Der Pull-Request-Lauf sollte zuerst billige Prüfungen ausführen: Formatierung, Linting, Typprüfung und kleine Unit Tests. Teure Integrationstests, End-to-End-Tests oder Container-Scans können parallel oder nachgelagert laufen, solange klare Regeln verhindern, dass riskante Änderungen ohne vollständige Prüfung gemerged werden.

Für Monorepos lohnt sich ein zweistufiges Modell. Auf Pull Requests laufen betroffene Checks möglichst schnell und parallel. Auf dem Hauptbranch läuft zusätzlich ein breiterer Validierungslauf, der Cache-Probleme, Merge-Effekte und unerwartete Abhängigkeiten erkennt. Für Releases sollten Deployments pro Artefakt getrennt sein. Nur weil ein Frontend geändert wurde, muss nicht jeder Worker neu ausgeliefert werden.

Typische Fehler in Monorepo-Pipelines

Der häufigste Fehler ist eine Pipeline, die aus Angst vor Komplexität immer alles macht. Das ist am Anfang bequem, wird aber mit jedem Service teurer. Der zweite Fehler ist das Gegenteil: zu aggressive Optimierung ohne verlässliche Abhängigkeitsanalyse. Dann werden Jobs übersprungen, die eigentlich wichtig wären. Beide Extreme führen zu Frust.

Ein weiterer Klassiker ist Cache-Wildwuchs. Viele Teams legen mehrere große Caches an, ohne zu messen, ob sie wirklich helfen. Caches haben Kosten: Upload, Download, Speicherplatz und Fehlersuche. Wenn ein Cache länger geladen wird als die frische Installation dauern würde, ist er kein Gewinn. Deshalb sollten Pipeline-Zeiten regelmäßig ausgewertet werden: Installationszeit, Build-Zeit, Testzeit, Queue-Zeit und Cache-Hit-Rate gehören in ein kleines Dashboard oder zumindest in wiederkehrende Reviews.

Rollout in bestehenden Teams

Wer bereits ein großes Monorepo betreibt, sollte nicht versuchen, die gesamte CI/CD-Landschaft in einem Schritt umzubauen. Besser ist ein kontrollierter Einstieg mit einem klar abgegrenzten Bereich. Zuerst wird ein Abhängigkeitsgraph eingeführt, dann ein betroffenes Projekt beschleunigt, danach werden weitere Jobs umgestellt. Parallel sollte es jederzeit einen manuellen Full-Run geben, damit Teams bei Unsicherheit die komplette Validierung starten können.

Auch Ownership gehört zum Rollout. Jede Pipeline-Stufe braucht Verantwortliche. Wenn niemand für den Cache-Key, die Testdaten oder den Deployment-Job zuständig ist, veraltet das Setup. Monorepos funktionieren langfristig nur, wenn Plattform- und Produktteams gemeinsam an Standards arbeiten: klare Templates, wiederverwendbare Jobs und wenige, gut dokumentierte Sonderfälle.

Fazit: Schnell wird es durch klare Grenzen

CI/CD für Monorepos wird nicht durch einzelne Tricks gut, sondern durch eine Kombination aus Struktur, Abhängigkeitswissen und messbarer Optimierung. Wer betroffene Projekte sauber erkennt, Caches bewusst invalidiert und Deployments pro Artefakt trennt, bekommt schnelle Pipelines ohne blinde Risiken. Das Ziel ist nicht, jeden Lauf maximal kurz zu machen. Das Ziel ist, genau die Prüfungen auszuführen, die für die jeweilige Änderung Vertrauen schaffen.

Für kleine und mittlere DevOps-Teams ist das besonders wichtig. Eine Monorepo-Pipeline soll Zusammenarbeit erleichtern, nicht jede Änderung ausbremsen. Mit konservativer Affected-Logik, wenigen verlässlichen Cache-Ebenen und regelmäßigem Messen lässt sich dieser Punkt gut erreichen.

Emre Hayta
Über den Autor
Emre Hayta
DevOps Engineer & IT Solution Architect · 15+ Jahre IT-Erfahrung

Ich unterstütze KMU in Oberösterreich und im DACH-Raum bei IT-Automatisierung, Infrastruktur und pragmatischer IT-Betreuung.

Mehr über mich