Monorepo vs Multirepo #
Salah satu keputusan pertama yang perlu dibuat saat mengorganisasi konfigurasi Terraform di skala tim adalah: taruh semua di satu repository, atau pisahkan ke beberapa repository? Tidak ada jawaban universal yang berlaku untuk semua konteks. Monorepo mempermudah visibilitas dan refactoring lintas konfigurasi; multirepo memberikan isolasi dan ownership yang lebih jelas. Pilihannya bergantung pada ukuran tim, arsitektur infrastruktur, dan bagaimana kamu ingin mengelola dependency antar komponen.
flowchart LR
subgraph Mono ["Monorepo"]
M1["networking/"]
M2["compute/"]
M3["database/"]
M4["shared modules/"]
end
subgraph Multi ["Multirepo"]
N1["infra-network\n(repo)"]
N2["infra-compute\n(repo)"]
N3["infra-db\n(repo)"]
end
style M1 fill:#3b82f6,stroke:#1e40af,color:#fff
style M2 fill:#3b82f6,stroke:#1e40af,color:#fff
style M3 fill:#3b82f6,stroke:#1e40af,color:#fff
style M4 fill:#8b5cf6,stroke:#6d28d9,color:#fff
style N1 fill:#10b981,stroke:#059669,color:#fff
style N2 fill:#10b981,stroke:#059669,color:#fff
style N3 fill:#10b981,stroke:#059669,color:#fffMonorepo: Semua di Satu Tempat #
STRUKTUR MONOREPO TIPIKAL:
infra-repo/
├── modules/ ← Shared modules
│ ├── networking/
│ ├── compute/
│ └── database/
│
├── environments/
│ ├── dev/
│ │ ├── networking/
│ │ ├── compute/
│ │ └── database/
│ ├── staging/
│ │ └── ...
│ └── production/
│ └── ...
│
├── .github/workflows/ ← Satu CI/CD pipeline
├── .gitignore
└── README.md
Semua infrastruktur ada di satu repository, dikelola bersama.
KEUNTUNGAN MONOREPO:
✓ Visibilitas penuh — semua perubahan terlihat di satu tempat
✓ Refactoring lebih mudah — ubah module, sekaligus update semua pemanggilnya
✓ Dependency antar konfigurasi lebih mudah dilacak
✓ Satu CI/CD pipeline untuk semua
✓ Lebih mudah untuk tim kecil yang mengelola semua infrastruktur
✓ Tidak ada versioning complexity antar module dan pemanggilnya
KELEMAHAN MONOREPO:
✗ Repository bisa jadi besar dan lambat seiring waktu
✗ Satu commit bisa mempengaruhi CI/CD untuk semua komponen
✗ Akses kontrol lebih sulit (sulit restrict tim tertentu ke folder tertentu)
✗ Perubahan modul yang tidak hati-hati bisa breaking semua pemanggilnya
✗ Coupling yang lebih ketat antar tim
Multirepo: Satu Repository per Komponen #
STRUKTUR MULTIREPO TIPIKAL:
infra-networking-repo/
├── modules/vpc/
├── environments/dev/
├── environments/staging/
└── environments/production/
infra-compute-repo/
├── modules/ec2/
├── modules/asg/
└── environments/...
infra-database-repo/
├── modules/rds/
└── environments/...
infra-modules-repo/ ← Shared modules di repo terpisah
├── networking/
├── compute/
└── database/
# Versi: v1.0.0, v1.1.0, v2.0.0
Setiap tim punya repository sendiri dengan akses dan pipeline terpisah.
KEUNTUNGAN MULTIREPO:
✓ Isolasi yang jelas — perubahan di satu repo tidak mempengaruhi yang lain
✓ Akses kontrol per-repository — tim database tidak bisa modifikasi networking
✓ Pipeline CI/CD lebih spesifik dan lebih cepat
✓ Module bisa punya versioning sendiri (v1.0, v1.1, v2.0)
✓ Tim bisa bergerak lebih independen
KELEMAHAN MULTIREPO:
✗ Visibilitas berkurang — sulit melihat gambaran besar infrastruktur
✗ Dependency management kompleks — harus kelola versi module antar repo
✗ Refactoring lintas repo lebih sulit dan perlu koordinasi
✗ Duplikasi pattern/konvensi jika tidak ada shared guidelines
✗ Overhead management lebih banyak (banyak repo, banyak pipeline)
Memilih Berdasarkan Konteks #
PILIH MONOREPO JIKA:
Tim kecil (< 5 engineer):
Overhead multirepo tidak sebanding, semua orang sudah tahu semua
infrastruktur, monorepo memberikan visibilitas yang dibutuhkan
Infrastruktur yang saling terkait erat:
Networking, compute, dan database sering berubah bersama
Refactoring lintas komponen sering terjadi
Baru mulai dengan Terraform:
Mulai sederhana, pecah menjadi multirepo nanti jika perlu
"Premature separation" lebih berbahaya dari monorepo yang tumbuh besar
Satu tim yang mengelola semua infrastruktur:
Tidak ada kebutuhan isolasi antar tim
PILIH MULTIREPO JIKA:
Tim besar dengan ownership yang jelas:
Tim A hanya touch networking, Tim B hanya touch database
Isolasi akses penting untuk governance
Module yang dipakai banyak tim:
Module perlu punya versi sendiri agar bisa di-upgrade secara bertahap
Breaking change di module tidak langsung mempengaruhi semua pemanggilnya
Compliance requirement:
Audit harus terpisah per domain (network audit, data audit)
Akses ke production database config tidak boleh ada di repo yang sama
dengan compute
Infrastruktur yang sudah mature dan stabil:
Komponen sudah jarang refactoring lintas domain
Pemisahan sudah natural sesuai ownership tim
Hybrid: Monorepo per Domain #
Pendekatan yang sering dipakai oleh tim menengah ke besar adalah monorepo per domain — satu repo untuk networking, satu repo untuk platform, satu repo untuk aplikasi, dan satu repo khusus untuk shared modules.
HYBRID STRUCTURE:
infra-foundation-repo/ ← Tim Platform / Infrastructure
├── networking/
├── security/
└── shared-services/
infra-platform-repo/ ← Tim Platform Engineering
├── kubernetes/
├── observability/
└── cicd-infrastructure/
infra-app-repo/ ← Tim Application
├── environments/dev/
├── environments/staging/
└── environments/production/
terraform-modules-repo/ ← Tim Platform — dipakai semua
├── vpc/
├── eks/
├── rds/
└── CHANGELOG.md
Ini memberikan isolasi yang cukup tanpa fragmentasi berlebihan.
Praktik yang Berlaku di Kedua Pendekatan #
Ada beberapa praktik yang penting terlepas dari monorepo atau multirepo.
# 1. Satu sumber kebenaran untuk versi Terraform
# Gunakan .terraform-version atau required_version di semua konfigurasi
terraform {
required_version = ">= 1.6, < 2.0"
}
# 2. Lock file selalu di-commit
# .terraform.lock.hcl harus ada di .gitignore EXCEPTION
# (exclude semua tapi include lock file)
# .gitignore:
# .terraform/
# !.terraform.lock.hcl ← khusus ini di-include
# 3. CODEOWNERS untuk kontrol review
# .github/CODEOWNERS:
# /environments/production/ @infrastructure-team @senior-engineers
# /modules/ @platform-team
# 4. Konvensi direktori yang konsisten
# Terlepas dari monorepo/multirepo, struktur internal harus seragam
# environments/
# dev/ staging/ production/
# (bukan: dev/ stg/ prod/ — inkonsistensi membingungkan)
flowchart TD
A["Small team\nfew services"] --> B["Monorepo ✅"]
C["Large team\nmany services"] --> D["Multirepo ✅"]
E["Microservices\nstrong ownership"] --> D
F["Shared infra\nrefactoring needed"] --> B
style A fill:#3b82f6,stroke:#1e40af,color:#fff
style B fill:#10b981,stroke:#059669,color:#fff
style C fill:#f59e0b,stroke:#d97706,color:#fff
style D fill:#10b981,stroke:#059669,color:#fff
style E fill:#8b5cf6,stroke:#6d28d9,color:#fff
style F fill:#3b82f6,stroke:#1e40af,color:#fffHybrid Approach: Monorepo with Multi-State #
Pendekatan hybrid menggabungkan keuntungan monorepo (single source of truth) dengan multi-state (isolated blast radius).
# Struktur monorepo dengan state terpisah per komponen
infrastructure/
├── modules/ # Shared modules (monorepo advantage)
│ ├── networking/
│ ├── compute/
│ └── database/
├── environments/
│ ├── dev/
│ │ ├── networking/ # State terpisah
│ │ ├── compute/
│ │ └── database/
│ ├── staging/
│ └── production/
└── .github/workflows/ # Shared CI/CD config
flowchart TD
subgraph REPO["Monorepo"]
M["Shared Modules"]
E1["dev/networking"]
E2["dev/compute"]
E3["prod/networking"]
E4["prod/compute"]
end
subgraph STATE["Separate States"]
S1["state: dev-networking"]
S2["state: dev-compute"]
S3["state: prod-networking"]
S4["state: prod-compute"]
end
E1 --> S1
E2 --> S2
E3 --> S3
E4 --> S4
style REPO fill:#e3f2fd,stroke:#1565c0
style STATE fill:#fff3e0,stroke:#e65100Monorepo CI/CD Challenges #
# Masalah: build semua module saat ada perubahan kecil
# Solusi: detect changed paths dan hanya build yang berubah
# GitHub Actions: path filter
on:
push:
paths:
- 'infrastructure/networking/**'
# GitHub Actions: matrix strategy per component
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
networking: ${{ steps.changes.outputs.networking }}
compute: ${{ steps.changes.outputs.compute }}
steps:
- uses: dorny/paths-filter@v2
id: changes
with:
filters: |
networking:
- 'infrastructure/networking/**'
compute:
- 'infrastructure/compute/**'
plan-networking:
needs: detect-changes
if: needs.detect-changes.outputs.networking == 'true'
runs-on: ubuntu-latest
steps:
- run: cd infrastructure/networking && terraform plan
Shared Module Library #
# Monorepo: satu repo untuk semua modules dan environments
infrastructure/
├── modules/ # SHARED: semua environment pakai ini
│ ├── networking/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── compute/
│ └── database/
├── environments/ # Per-environment config
│ ├── dev/
│ │ └── main.tf # → source = "../../modules/networking"
│ ├── staging/
│ └── production/
└── .github/workflows/ # SHARED CI/CD config
flowchart TD
subgraph REPO["Monorepo"]
MOD["modules/
(SHARED)"]
DEV["environments/dev"]
STG["environments/staging"]
PRD["environments/production"]
end
MOD --> DEV
MOD --> STG
MOD --> PRD
style MOD fill:#e3f2fd,stroke:#1565c0
style PRD fill:#e8f5e9,stroke:#2e7d32Ringkasan #
- Tidak ada pilihan universally better — monorepo lebih baik untuk tim kecil dan infrastruktur yang saling terkait, multirepo lebih baik untuk tim besar dengan ownership yang jelas.
- Mulai dengan monorepo jika baru mulai — lebih mudah dipecah nanti sesuai kebutuhan, tapi sulit menggabungkan multirepo yang sudah ada.
- Multirepo membutuhkan module versioning — module di repo terpisah harus punya versioning eksplisit agar pemanggilnya bisa upgrade secara bertahap.
- Hybrid per-domain adalah sweet spot untuk tim menengah — satu repo per domain (networking, platform, app) dengan satu repo terpisah untuk shared modules.
- CODEOWNERS di GitHub/GitLab membantu enforce siapa yang harus review perubahan di direktori tertentu — penting untuk monorepo yang dikelola banyak tim.
- .terraform.lock.hcl harus di-commit di kedua pendekatan — memastikan semua orang dan pipeline menggunakan versi provider yang persis sama.
← Sebelumnya: Common Security Mistake Berikutnya: Lifecycle Management →