Monorepo — Panduan Lengkap Mengelola Banyak Proyek dalam Satu Repository
Pengenalan: Kenapa Monorepo Semakin Populer?
Monorepo semakin populer di dunia software development modern — dan bukan tanpa alasan. Perusahaan-perusahaan besar seperti Google, Meta, Microsoft, serta proyek open-source ternama seperti Babel, Jest, dan React, semuanya menggunakan pendekatan monorepo. Tapi sebenarnya apa sih monorepo itu, dan kenapa kamu harus mempertimbangkannya untuk tim kamu?
Dalam panduan lengkap ini, kita akan membahas semuanya — dari konsep dasar sampai tools yang bikin pengembangan monorepo jadi menyenangkan.
Daftar Isi
- Pengenalan
- Apa Itu Monorepo?
- Monorepo vs. Monolith
- Polyrepo: Pendekatan Tradisional
- Kenapa Memilih Monorepo?
- Fitur-Fitur Utama Monorepo
- Perbandingan Tools Monorepo
- Memilih Tool yang Tepat
- Memulai: Monorepo dengan Nx
- Memulai: Monorepo dengan Turborepo
- Best Practices
- Kesimpulan
Apa Itu Monorepo?
Monorepo adalah satu repository yang berisi beberapa proyek berbeda, dengan hubungan yang terdefinisi dengan jelas antar proyek tersebut.
Kata kunci-nya di sini adalah “hubungan yang terdefinisi dengan jelas.” Monorepo bukan sekadar menaruh semua kode ke dalam satu repository. Setiap proyek di dalam monorepo harus merupakan unit terpisah dengan batasan, dependensi, dan kepemilikan yang jelas.
Yang Bukan Monorepo
- Bukan sekadar “taruh kode di satu tempat” — Kalau kamu punya beberapa proyek dalam satu repo tapi tanpa hubungan yang terdefinisi, itu cuma folder berisi kode, bukan monorepo.
- Bukan monolith — Kalau repo berisi satu aplikasi besar tanpa pembagian menjadi bagian-bagian yang terenkapsulasi, itu cuma repo besar (monolitik). Monorepo yang baik justru kebalikan dari monolitik.
# Struktur monorepo yang terorganisir
my-monorepo/
├── apps/
│ ├── web-app/ # Frontend React
│ ├── mobile-app/ # Aplikasi React Native
│ └── api-server/ # Backend Node.js
├── packages/
│ ├── ui-components/ # Library UI bersama
│ ├── utils/ # Utilitas bersama
│ └── config/ # Konfigurasi bersama (ESLint, TypeScript, dll.)
├── package.json
├── nx.json # atau turbo.json
└── README.md
Diagram Struktur Monorepo
graph TD
A[Root Monorepo] --> B[apps/]
A --> C[packages/]
A --> D[tools/]
A --> E[configs/]
B --> F[web-app]
B --> G[mobile-app]
B --> H[api-server]
C --> I[ui-components]
C --> J[utils]
C --> K[config-eslint]
C --> L[config-typescript]
F --> I
F --> J
G --> I
G --> J
H --> J
H --> K
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#fce4ec
Monorepo vs. Monolith
Ini salah satu miskonsepsi paling umum. Yuk kita luruskan:
| Aspek | Monorepo | Monolith |
|---|---|---|
| Struktur | Beberapa proyek berbeda dalam satu repo | Satu aplikasi yang tightly-coupled |
| Batasan | Batasan modul dan API yang jelas | Batasan antar komponen tidak jelas |
| Deployment | Deploy independen per proyek | Satu unit deployment |
| Skalabilitas | Bisa scale dengan tooling yang tepat | Semakin sulit di-scale |
| Kepemilikan Tim | Setiap tim punya proyek masing-masing | Satu tim atau shared ownership |
Monorepo yang baik justru mendorong modularitas dengan memudahkan berbagi kode sambil menjaga proyek tetap independen dan bisa di-deploy secara terpisah.
Polyrepo: Pendekatan Tradisional
Polyrepo (kebalikan dari monorepo) adalah pendekatan standar di mana setiap tim, aplikasi, atau library punya repository sendiri. Walaupun polyrepo menawarkan otonomi tim, otonomi itu datang melalui isolasi, dan isolasi justru menghambat kolaborasi.
Masalah Umum Polyrepo
1. Berbagi Kode Itu Ribet
Untuk berbagi kode antar repository, kamu perlu membuat repo terpisah untuk shared code, setup CI/CD, konfigurasi package publishing, dan mengelola versioning. Overhead-nya cukup besar.
# Polyrepo: berbagi kode itu menyakitkan
team-a-repo/ → publish @company/shared-utils v1.2.0
team-b-repo/ → depends on @company/shared-utils v1.1.0 😬
team-c-repo/ → depends on @company/shared-utils v1.0.0 😱
2. Duplikasi Kode yang Signifikan
Karena setup shared repo itu ribet, tim-tim sering menulis ulang utilitas umum di setiap repo — membuang waktu dan menambah beban maintenance.
3. Cross-Repo Changes yang Mahal
Ada bug kritis di shared library? Kamu harus fix di library repo, publish versi baru, lalu update dan test setiap consumer repo secara terpisah. Koordinasi versi antar repo itu mimpi buruk.
4. Tooling yang Tidak Konsisten
Setiap proyek pakai command set yang berbeda untuk testing, building, linting, dan deploying. Ini bikin developers harus berpikir ekstra saat pindah-pindah proyek.
Kenapa Memilih Monorepo?
Monorepo menyelesaikan masalah-masalah polyrepo dengan elegan:
Perbandingan Workflow Polyrepo vs Monorepo
flowchart TD
subgraph "Workflow Polyrepo"
A1[Fix bug shared library] --> B1[Update library di lib-repo]
B1 --> C1[Publish versi baru v2.1.0]
C1 --> D1[Update consumer-repo-1 ke v2.1.0]
C1 --> E1[Update consumer-repo-2 ke v2.1.0]
C1 --> F1[Update consumer-repo-3 ke v2.1.0]
D1 --> G1[Test consumer-repo-1]
E1 --> H1[Test consumer-repo-2]
F1 --> I1[Test consumer-repo-3]
G1 --> J1[Deploy consumer-repo-1]
H1 --> K1[Deploy consumer-repo-2]
I1 --> L1[Deploy consumer-repo-3]
end
subgraph "Workflow Monorepo"
A2[Fix bug shared library] --> B2[Update library di packages/]
B2 --> C2[Commit semua perubahan bersama]
C2 --> D2[Jalankan test yang terdampak]
D2 --> E2[Deploy semua app yang terdampak]
end
style A1 fill:#ffebee
style A2 fill:#e8f5e8
style B1 fill:#ffebee
style B2 fill:#e8f5e8
Tanpa Overhead untuk Proyek Baru
Pakai setup CI yang sudah ada. Tidak perlu publish versioned packages kalau semua consumer ada di repo yang sama.
# Dengan Nx: buat app baru dalam hitungan detik
npx nx g @nx/react:app my-new-app
# Dengan Turborepo: tinggal tambah folder baru
mkdir apps/my-new-app
Atomic Commits Lintas Proyek
Semua bekerja bersama di setiap commit. Fix shared library dan semua consumer-nya dalam satu commit — tanpa breaking changes, tanpa koordinasi versi.
# Satu commit yang update shared lib + semua consumer
git commit -m "fix: update validation logic across all apps"
Satu Versi untuk Semuanya
Tidak perlu khawatir soal versi third-party library yang tidak kompatibel antar proyek. Satu package.json (atau root dependency manager) memastikan konsistensi.
Mobilitas Developer
Developer mendapat cara yang konsisten untuk build dan test di berbagai tools dan teknologi. Mereka bisa dengan percaya diri berkontribusi ke proyek tim lain dan memverifikasi bahwa perubahan mereka aman.
Fitur-Fitur Utama Monorepo
Saat memilih tool monorepo, berikut fitur-fitur yang perlu kamu perhatikan:
⚡ Kecepatan (Fast)
Local Computation Caching
Simpan dan putar ulang output file dan proses. Tidak pernah build atau test hal yang sama dua kali di mesin yang sama.
# Run pertama: build semuanya
npx nx build my-app # Butuh 45 detik
# Run kedua: di-restore dari cache
npx nx build my-app # Butuh 0.5 detik ⚡
Local Task Orchestration
Jalankan task dalam urutan yang benar dan secara paralel, menghormati dependency graph.
# Nx menjalankan task secara paralel, menghormati dependensi
npx nx run-many --target=build --all --parallel=5
Distributed Computation Caching
Berbagi cache artifacts di seluruh organisasi kamu, termasuk CI agents. Tidak ada seorang pun di tim kamu yang perlu build atau test hal yang sama dua kali.
Distributed Task Execution
Distribusikan satu command ke banyak mesin CI sambil mempertahankan developer experience seperti menjalankannya secara lokal.
Detecting Affected Projects
Hanya build dan test yang terdampak oleh perubahan, bukan seluruh repo.
# Hanya test proyek yang terdampak perubahan sejak main
npx nx affected --target=test --base=main
# Turborepo equivalent
npx turbo run test --filter=...[origin/main]
🧠 Mudah Dipahami (Understandable)
Workspace Analysis
Memahami project graph dari workspace secara otomatis dengan menganalisis package.json, source file, dan konfigurasi.
Dependency Graph Visualization
Visualisasi hubungan dependensi antar proyek dan task secara interaktif.
graph TD
subgraph "Apps"
A[web-app]
B[mobile-app]
C[api-server]
end
subgraph "UI Libraries"
D[ui-button]
E[ui-form]
F[ui-modal]
end
subgraph "Shared Libraries"
G[utils-date]
H[utils-string]
I[config-eslint]
J[config-typescript]
end
A --> D
A --> E
A --> F
A --> G
A --> H
B --> D
B --> E
B --> G
B --> H
C --> G
C --> H
C --> I
C --> J
D --> G
E --> G
F --> H
style A fill:#e3f2fd
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#fff3e0
style F fill:#fff3e0
style G fill:#fce4ec
style H fill:#fce4ec
style I fill:#e1f5fe
style J fill:#e1f5fe
# Nx: buka visualisasi graph interaktif
npx nx graph
# Turborepo: generate graph
npx turbo run build --graph
🔧 Mudah Dikelola (Manageable)
Source Code Sharing
Mudah berbagi potongan source code antar proyek tanpa perlu publish packages.
Consistent Tooling
Pengalaman yang konsisten terlepas dari teknologi yang dipakai setiap proyek — JavaScript, TypeScript, Go, Rust, Java, dll.
Code Generation
Scaffold proyek, komponen, dan modul baru dengan generator bawaan.
# Nx: generate komponen React baru
npx nx g @nx/react:component my-button --project=ui-lib
# Nx: generate library Node.js baru
npx nx g @nx/node:lib shared-utils
Project Constraints dan Visibility
Definisikan aturan untuk membatasi hubungan dependensi. Tandai proyek sebagai private, pisahkan frontend dari backend, dan terapkan batasan arsitektur.
// nx.json - enforce module boundaries
{
"targetDefaults": {},
"plugins": [
{
"plugin": "@nx/eslint/plugin",
"options": {
"targetName": "lint"
}
}
]
}
Perbandingan Tools Monorepo
Berikut perbandingan tools monorepo utama:
Nx
“Nx optimizes your builds, scales your CI, and fixes failed PRs.”
- Cocok untuk: Monorepo management berfitur lengkap dengan DX yang excellent
- Dukungan bahasa: JavaScript/TypeScript, plus plugin untuk Go, Rust, Java, dll.
- Keunggulan: Visualizer graph interaktif, code generator powerful, distributed task execution, dukungan MCP server
- Cache: Lokal + remote (via Nx Cloud)
Turborepo (oleh Vercel)
“The high-performance build system for JavaScript & TypeScript codebases.”
- Cocok untuk: Task running yang simpel dan cepat di monorepo JS/TS
- Dukungan bahasa: JavaScript/TypeScript
- Keunggulan: Zero-config caching, incremental builds, remote caching via Vercel
- Cache: Lokal + remote
Bazel (oleh Google)
“A fast, scalable, multi-language and extensible build system.”
- Cocok untuk: Repository berukuran masif (miliaran baris kode), proyek polyglot
- Dukungan bahasa: Hampir semua bahasa via build rules
- Keunggulan: Transparent remote execution, distributed execution paling matang
- Cache: Lokal + remote
Lerna (di-maintain oleh tim Nx)
“A tool for managing JavaScript projects with multiple packages.”
- Cocok untuk: Publishing npm packages dari monorepo
- Dukungan bahasa: JavaScript/TypeScript
- Keunggulan: Workflow versioning dan publishing, didukung Nx under the hood sejak v6
- Cache: Lokal + remote (via Nx Cloud)
moon (oleh moonrepo)
“A task runner and monorepo management tool for the web ecosystem.”
- Cocok untuk: Proyek web yang butuh integrated toolchain
- Dukungan bahasa: JavaScript/TypeScript, plus dukungan bahasa tier 2
- Keunggulan: Built-in toolchain management, native code generation, project constraints
Pants (oleh Pants Build)
“A fast, scalable, user-friendly build system for codebases of all sizes.”
- Cocok untuk: Repo polyglot, terutama Python + bahasa backend
- Dukungan bahasa: Python, Java, Scala, Go, Shell, Docker
- Keunggulan: Inferensi dependensi otomatis via static analysis, transparent remote execution
Rush (oleh Microsoft)
“Geared for large monorepos with lots of teams and projects.”
- Cocok untuk: Monorepo enterprise besar berbasis JavaScript/TypeScript
- Dukungan bahasa: JavaScript/TypeScript
- Keunggulan: NPM dependency approvals, version policies, integrasi BuildXL
Tabel Perbandingan Fitur
| Fitur | Nx | Turborepo | Bazel | Lerna | moon | Pants | Rush |
|---|---|---|---|---|---|---|---|
| Local caching | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Task orchestration | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Remote caching | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Distributed execution | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | 🔧 |
| Affected detection | ✅ | ✅ | 🔧 | ✅ | ✅ | ✅ | ✅ |
| Graph visualization | ✅ | ✅ | ✅ | ✅ | ✅ | 🔧 | 🔧 |
| Consistent tooling | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Code generation | ✅ | 🔧 | 🔧 | 🔧 | ✅ | ✅ | 🔧 |
| Project constraints | ✅ | 🔧 | ✅ | 🔧 | ✅ | 🔧 | ✅ |
✅ = Didukung native | 🔧 = Implementasi sendiri | ❌ = Tidak didukung
Memilih Tool yang Tepat
Berikut panduan cepat untuk memilih:
- Proyek JS/TS kecil-menengah, butuh yang simpel → Turborepo
- Monorepo berfitur lengkap dengan DX terbaik → Nx
- Codebase polyglot berukuran masif (skala Google) → Bazel
- Perlu publish npm packages → Lerna (dengan Nx)
- Ekosistem web dengan integrated tooling → moon
- Repo polyglot berat di Python/backend → Pants
- Enterprise besar JS/TS dengan governance ketat → Rush
Memulai: Monorepo dengan Nx
Berikut cara setup monorepo dengan Nx:
# Buat workspace Nx baru
npx create-nx-workspace@latest my-monorepo
# Pilih preset (React, Angular, Node, dll.)
# atau mulai dengan workspace kosong
cd my-monorepo
Menambah Proyek
# Tambah aplikasi React
npx nx g @nx/react:app web-app
# Tambah Node.js API
npx nx g @nx/node:app api
# Tambah shared library
npx nx g @nx/react:lib ui-components
Menjalankan Task
# Build proyek tertentu
npx nx build web-app
# Jalankan test untuk proyek yang terdampak
npx nx affected --target=test
# Visualisasikan dependency graph
npx nx graph
# Jalankan beberapa task secara paralel
npx nx run-many --target=build --all --parallel=5
Konfigurasi Nx
// nx.json
{
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"cache": true
},
"test": {
"cache": true
},
"lint": {
"cache": true
}
},
"defaultBase": "main"
}
Memulai: Monorepo dengan Turborepo
# Buat Turborepo baru
npx create-turbo@latest my-turborepo
cd my-turborepo
Struktur Proyek
my-turborepo/
├── apps/
│ ├── web/ # Aplikasi Next.js
│ └── docs/ # Situs dokumentasi
├── packages/
│ ├── ui/ # Komponen UI bersama
│ ├── eslint-config/ # Konfigurasi ESLint bersama
│ └── typescript-config/ # Konfigurasi TS bersama
├── turbo.json
└── package.json
Konfigurasi Turborepo
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
Menjalankan Task
# Build semua proyek
npx turbo run build
# Jalankan dev server
npx turbo run dev
# Jalankan task hanya untuk package tertentu
npx turbo run build --filter=web
# Jalankan task yang terdampak
npx turbo run test --filter=...[origin/main]
Best Practices
1. Definisikan Batasan Proyek yang Jelas
Organisasikan monorepo kamu dengan batasan yang jelas antara apps dan libraries:
monorepo/
├── apps/ # Aplikasi yang bisa di-deploy
├── packages/ # Library bersama
├── tools/ # Build tools dan script
└── configs/ # Konfigurasi bersama
2. Gunakan Module Boundaries
Pastikan proyek backend tidak mengimpor dari proyek frontend dan sebaliknya. Tools seperti Nx menyediakan lint rule bawaan untuk ini.
// .eslintrc.json dengan Nx module boundary rules
{
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{
"depConstraints": [
{ "sourceTag": "scope:frontend", "onlyDependOnLibsWithTags": ["scope:shared"] },
{ "sourceTag": "scope:backend", "onlyDependOnLibsWithTags": ["scope:shared"] }
]
}
]
}
}
3. Manfaatkan Cache Secara Agresif
Aktifkan local dan remote caching. Ini bisa mengurangi waktu CI sebesar 50-90%.
4. Gunakan Affected Commands di CI
Jangan pernah build dan test semuanya — hanya yang terdampak oleh perubahan saat ini.
# Contoh GitHub Actions
- name: Test affected
run: npx nx affected --target=test --base=origin/main
5. Buat Shared Libraries yang Kecil dan Fokus
Jangan bikin satu library “shared” yang berisi semuanya. Buat library-library kecil yang fokus:
packages/
├── ui-button/
├── ui-form/
├── utils-date/
├── utils-string/
└── config-eslint/
6. Otomatisasi Update Dependensi
Gunakan tools seperti Renovate atau Dependabot untuk menjaga dependensi tetap sinkron di seluruh monorepo.
7. Standarisasi Development Commands
Pastikan setiap proyek menggunakan command yang sama untuk task umum:
nx build <project>
nx test <project>
nx lint <project>
nx serve <project>
Kesimpulan
Monorepo lebih dari sekadar strategi organisasi kode — ini adalah perubahan cara organisasi kamu berkolaborasi dan mengirimkan software. Dengan mengkonsolidasikan proyek-proyek ke dalam satu repository dengan hubungan yang terdefinisi dengan jelas, kamu mendapat:
- Pengembangan lebih cepat melalui code sharing dan caching
- Kolaborasi lebih baik dengan atomic commits dan tooling yang konsisten
- Kualitas kode meningkat melalui module boundaries yang di-enforce
- CI/CD lebih simpel dengan affected commands dan distributed execution
Ekosistem tooling sudah sangat matang, dengan pilihan untuk setiap ukuran tim dan tech stack. Entah kamu pilih Nx untuk fiturnya yang komprehensif, Turborepo untuk kesederhanaannya, atau Bazel untuk skalanya, kuncinya adalah mulai dari kecil dan kembangkan praktik monorepo kamu secara bertahap.
Ingat: monorepo bukan monolith. Kalau dilakukan dengan benar, justru sebaliknya — cara yang modular, scalable, dan kolaboratif untuk mengelola codebase kamu.
Referensi Lanjutan
- monorepo.tools — Resource komprehensif tentang monorepo dan perbandingan tools
- Dokumentasi Nx — Dokumentasi lengkap Nx monorepo
- Turborepo Docs — Dokumentasi resmi Turborepo
- Dokumentasi Bazel — Dokumentasi build system Bazel
- Misconceptions about Monorepos: Monorepo != Monolith — Bacaan bagus tentang mitos monorepo