ProCust
Monorepo mit Turborepo: Mehrere Pakete sauber verwalten

Monorepo mit Turborepo: Mehrere Pakete sauber verwalten

Wann sich ein Monorepo lohnt, wie Turborepo Builds mit Caching und Task-Graphen beschleunigt und wie Sie Apps und gemeinsame Pakete strukturieren.

Kurz gefasst: Ein Monorepo bündelt mehrere zusammengehörige Projekte, etwa Web-App, Backend, Admin-Oberfläche und gemeinsame Bibliotheken, in einem einzigen Git-Repository. Turborepo ist ein Build-Werkzeug für JavaScript- und TypeScript-Monorepos, das Aufgaben wie Build, Tests und Linting in der richtigen Reihenfolge ausführt und Ergebnisse zwischenspeichert, sodass unveränderte Pakete nicht neu gebaut werden. Es lohnt sich, sobald mehrere Anwendungen Code teilen und Änderungen über Paketgrenzen hinweg zusammen ausgeliefert werden sollen.

Was ein Monorepo ist und welche Probleme es löst

Viele Softwareprojekte bestehen aus mehreren Teilen, die eng zusammenhängen: eine Next.js-Website, eine mobile App, eine API und Pakete mit gemeinsamen Typen, UI-Komponenten oder Validierungsregeln. Liegen diese Teile in getrennten Repositories, entsteht schnell Reibung. Eine Änderung an einem gemeinsamen Datentyp erfordert dann einen Release des Pakets, ein Versions-Update in jedem abhängigen Projekt und mehrere Pull Requests, die zeitlich abgestimmt werden müssen.

Im Monorepo passiert dieselbe Änderung in einem einzigen Commit. Der TypeScript-Compiler zeigt sofort, welche Anwendungen angepasst werden müssen, und alle Teile werden gemeinsam getestet. Das ist besonders wertvoll, wenn Frontend und Backend dieselben Typen nutzen, wie wir es in unserem Leitfaden zur Full-Stack-Entwicklung mit TypeScript beschreiben.

Ein Monorepo ist allerdings kein Selbstzweck. Ohne passendes Werkzeug wird jeder Build langsamer, weil bei jeder Änderung alles neu gebaut und getestet wird. Genau hier setzt Turborepo an.

Wie Turborepo funktioniert

Workspaces als Grundlage

Turborepo ersetzt nicht den Paketmanager. Es baut auf den Workspaces von npm, pnpm, Yarn oder Bun auf, die mehrere Pakete in einem Repository verwalten und lokal miteinander verlinken. Eine typische Struktur sieht so aus:

apps/
  web/        # Next.js-Anwendung
  admin/      # internes Dashboard
  api/        # Backend
packages/
  ui/         # gemeinsame React-Komponenten
  types/      # gemeinsame TypeScript-Typen
  config/     # ESLint- und TypeScript-Konfiguration

Der Task-Graph

In der Datei turbo.json legen Sie fest, welche Aufgaben es gibt und wovon sie abhängen. Die Angabe "dependsOn": ["^build"] bedeutet zum Beispiel: Bevor eine App gebaut wird, müssen alle Pakete gebaut sein, von denen sie abhängt. Turborepo leitet daraus die Reihenfolge ab und führt alles, was unabhängig ist, parallel aus.

{
  "tasks": {
    "build": { "dependsOn": ["^build"], "outputs": [".next/**", "dist/**"] },
    "test": { "dependsOn": ["^build"] },
    "lint": {}
  }
}

Caching

Der größte Zeitgewinn entsteht durch das Caching. Turborepo berechnet für jede Aufgabe einen Hash aus Quellcode, Abhängigkeiten und Konfiguration. Hat sich nichts geändert, wird das gespeicherte Ergebnis wiederverwendet, statt die Aufgabe erneut auszuführen. Mit einem Remote Cache teilen sich Entwickler und CI-Server diese Ergebnisse. Was einmal auf einem Rechner gebaut wurde, muss in der Pipeline nicht noch einmal gebaut werden.

Gezielte Ausführung

Mit Filtern lassen sich Aufgaben auf einzelne Pakete beschränken, etwa turbo run build --filter=web. In der CI-Pipeline kann man so nur die Pakete prüfen, die von einer Änderung tatsächlich betroffen sind. Wie Sie eine solche Pipeline aufsetzen, zeigt unser Praxisleitfaden für CI/CD-Pipelines.

Ein Monorepo sinnvoll strukturieren

Die Trennung zwischen apps und packages hat sich bewährt. Apps werden ausgeliefert, Pakete werden von Apps verwendet. Pakete sollten eine klare Aufgabe haben und nicht zu einer Sammelstelle für alles werden, was irgendwo zweimal vorkommt.

Gemeinsame Konfiguration für ESLint, Prettier und TypeScript gehört in ein eigenes Paket. So gelten in allen Projekten dieselben Regeln, und eine Änderung wirkt überall. Mehr zu sinnvollen Konventionen lesen Sie in unseren Clean-Code-Prinzipien für TypeScript.

Ein typisches gemeinsames Paket ist die UI-Bibliothek. Wer ein Design System aufbaut, legt die Komponenten dort ab und nutzt sie in Website, Admin-Oberfläche und Kundenportal gleichermaßen.

Wann Turborepo nicht die richtige Wahl ist

Für ein einzelnes Projekt ohne geteilten Code bringt ein Monorepo nur zusätzliche Struktur. Auch wenn Teams völlig unabhängig voneinander arbeiten und eigene Release-Zyklen haben, können getrennte Repositories die bessere Wahl sein.

Turborepo konzentriert sich auf schnelle Task-Ausführung und Caching. Wer zusätzlich Code-Generatoren, strikte Regeln für erlaubte Abhängigkeiten zwischen Paketen oder Unterstützung für viele Sprachen braucht, sollte sich Nx ansehen. Für sehr kleine Setups reichen manchmal auch reine pnpm-Workspaces ohne zusätzliches Werkzeug.

Häufige Fragen (FAQ)

Wird ein Monorepo bei vielen Paketen nicht unübersichtlich?

Nicht, wenn die Struktur klar ist und jedes Paket eine eindeutige Aufgabe hat. Mit Filtern arbeitet jedes Teammitglied ohnehin meist nur an wenigen Paketen. Die Übersicht leidet eher, wenn dieselbe Logik in mehreren Repositories kopiert wird.

Braucht Turborepo einen kostenpflichtigen Remote Cache?

Nein. Lokales Caching funktioniert ohne zusätzliche Dienste. Für den Remote Cache gibt es die Anbindung an Vercel oder selbst gehostete Lösungen, die das offene Cache-Protokoll unterstützen.

Kann ich ein bestehendes Projekt in ein Monorepo überführen?

Ja. Meist beginnt man damit, die bestehenden Repositories mit ihrer Git-Historie in ein gemeinsames Repository zu verschieben und Workspaces einzurichten. Turborepo lässt sich danach schrittweise ergänzen.

Wie werden Pakete im Monorepo versioniert?

Interne Pakete, die nur innerhalb des Repositorys genutzt werden, brauchen oft gar keine eigene Version. Werden Pakete veröffentlicht, hilft ein Werkzeug wie Changesets, Versionsnummern und Changelogs zu pflegen.

Fazit

Ein Monorepo zahlt sich aus, wenn mehrere Anwendungen Code teilen und gemeinsam weiterentwickelt werden. Turborepo sorgt dafür, dass dieser Komfort nicht mit langen Build-Zeiten bezahlt wird, vorausgesetzt, Task-Graph und Caching werden von Anfang an sauber konfiguriert.

Wenn Sie mehrere Anwendungen auf eine gemeinsame Codebasis bringen möchten, sprechen Sie mit uns über Webentwicklung.