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:#fff

Monorepo: 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:#fff

Hybrid 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:#e65100

Monorepo 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:#2e7d32

Ringkasan #

  • 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 →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact