Monorepo — Panduan Lengkap Mengelola Banyak Proyek dalam Satu Repository

Monorepo — Panduan Lengkap Mengelola Banyak Proyek dalam Satu Repository

12/14/2025 DevOps By Tech Writers
MonorepoDevOpsToolingNxTurborepoArsitekturDeveloper ExperienceCI/CD

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

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:

AspekMonorepoMonolith
StrukturBeberapa proyek berbeda dalam satu repoSatu aplikasi yang tightly-coupled
BatasanBatasan modul dan API yang jelasBatasan antar komponen tidak jelas
DeploymentDeploy independen per proyekSatu unit deployment
SkalabilitasBisa scale dengan tooling yang tepatSemakin sulit di-scale
Kepemilikan TimSetiap tim punya proyek masing-masingSatu 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

FiturNxTurborepoBazelLernamoonPantsRush
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 simpelTurborepo
  • Monorepo berfitur lengkap dengan DX terbaikNx
  • Codebase polyglot berukuran masif (skala Google)Bazel
  • Perlu publish npm packagesLerna (dengan Nx)
  • Ekosistem web dengan integrated toolingmoon
  • Repo polyglot berat di Python/backendPants
  • Enterprise besar JS/TS dengan governance ketatRush

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