5 Apps in einem Repository - Das Turborepo-Monorepo eines Solo-Entwicklers
Wie man mehrere Apps und Websites in einem einzigen Repository mit Turborepo verwaltet. Gemeinsame Konfiguration teilen, mit dem Cache Builds sparen und pro App deployen, aus der Praxis erklärt.
Das Wichtigste
Wer allein mehrere Apps baut, dessen Konfiguration zerstreut sich. Mit einem Turborepo-Monorepo teilt man eslint und tsconfig über packages, der turbo-Cache baut unveränderte Apps nicht neu, und mit --filter deployt man pro App.
Auf dieser Seite
Wer allein Apps baut, sammelt Repositories wie Staub. Eine App, eine Website, noch eine App... und irgendwann kopiert man die eslint-Konfiguration zum fünften Mal. Ich habe das alles in ein einziges Monorepo zusammengeführt.
Das echte Problem ist die verstreute Konfiguration
Bei vielen Repositories schmerzt nicht der Code am meisten, sondern die Konfiguration.
- eslint, prettier und tsconfig in jedes Repository kopieren
- Eine Regel ändern heißt: alle Repositories der Reihe nach anfassen
- Gemeinsame UI und Utilities sind zu klein, um sie auf npm zu veröffentlichen
Ein Monorepo dreht das um: Alles wird an einer Stelle geteilt.
Die Grundstruktur
apps/
├── web/ # 랜딩
├── blog/ # 이 블로그
├── wave/ # 오늘의 파도
└── ...
packages/
├── eslint-config/ # 공용 eslint
└── typescript-config/ # 공용 tsconfig
apps/* sind die tatsächlichen Deploy-Artefakte, packages/* enthält die von allen Apps geteilte Konfiguration und den gemeinsamen Code. Die tsconfig.json jeder App erbt einfach nur.
{ "extends": "@repo/typescript-config/nextjs.json" }
Regeln werden jetzt nur noch an einer Stelle in packages geändert.
Der turbo-Cache ist der Kern
Die eigentliche Waffe von Turborepo ist der Cache. Ändern sich die Inputs eines Tasks (Quellcode, Konfiguration) nicht, wird das vorherige Ergebnis direkt wiederverwendet.
turbo run build # 전체 빌드(바뀐 것만 실제로 돎)
turbo run build --filter=blog # blog 앱만
In turbo.json deklariert man nur die Abhängigkeiten zwischen Tasks und die Outputs.
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": [".next/**"] }
}
}
Ab dem zweiten Build heißt es "FULL TURBO", und alles ist in wenigen Sekunden fertig.
Pro App deployen
Auch mit einem einzigen Repository bleibt das Deployment pro App getrennt. Bei Docker schneidet turbo prune nur den Teilbaum der jeweiligen App heraus und hält das Image schlank.
turbo prune blog --docker # blog + 내부 의존성만 남긴 out/ 생성
Auch dieser Blog wurde so zugeschnitten und läuft per Docker auf einem Mini-PC. Diese Geschichte erzähle ich im Beitrag zum Self-Hosting.
Fazit
apps/*= Deploy-Artefakte,packages/*= geteilte Konfiguration- tsconfig und eslint per Vererbung an einer Stelle pflegen
- Der
turbo-Cache baut unveränderte Apps nicht neu - Mit
--filterundprunepro App deployen
Wer allein mehrere Produkte betreibt, für den ist ein Monorepo kein Luxus, sondern ein Überlebenswerkzeug.
Häufige Fragen
Ab wie vielen Apps lohnt sich ein Monorepo?
Schon ab 2 Apps lohnt es sich, sobald gemeinsame Konfiguration (eslint, tsconfig, UI) entsteht. Der Kern: Einstellungen an einer Stelle ändern und alle Apps übernehmen sie.
Werden die Builds dadurch nicht langsamer?
Im Gegenteil, sie werden schneller. turbo cached die Ergebnisse von Tasks, deren Inputs sich nicht geändert haben, und baut nur die geänderten Apps neu.
Ähnliche Beiträge
- 💻 Entwicklung
Einen MDX-Blog mit Next.js selbst bauen - So ist dieser Blog entstanden
Wie dieser Blog ohne CMS, nur mit Markdown-Dateien und dem Next.js 16 App Router entstanden ist. Ordnerstruktur, MDX-Setup und SEO, erklärt am echten Code.
- 💻 Entwicklung
Self-Hosting auf dem Mini-PC mit Docker + Cloudflare Tunnel
Wie man mit einem einzigen Mini-PC zu Hause mehrere Webdienste sicher öffentlich macht. HTTPS ohne offene Ports über Cloudflare Tunnel, betrieben mit Docker Compose.
- ☕ Alltag
Die Tagesroutine eines Solo-Entwicklers - Wie man allein nicht ausbrennt
Ohne Chef und ohne Kollegen zu arbeiten ist frei, aber man brennt schnell aus. Hier sind die Tagesroutine und ein paar Regeln, mit denen ich meinen Rhythmus halte.