Monorepo vs Polyrepo untuk Tim Kecil-Menengah

Pertanyaan monorepo vs polyrepo biasanya muncul begitu tim mulai punya lebih dari satu aplikasi yang saling terkait — misalnya backend Laravel, frontend Vue terpisah, dan satu atau dua service pendukung seperti worker antrian atau layanan AI. Dari pengalaman berpindah-pindah antara dua pendekatan ini di tim kecil-menengah, saya melihat keputusan ini sering diambil terlalu cepat, padahal dampaknya baru terasa saat jumlah service bertambah dan proses deploy mulai terasa berat.

Tidak ada jawaban benar-salah di sini. Yang ada adalah trade-off antara kemudahan koordinasi dan kompleksitas tooling, yang bergeser tergantung ukuran tim dan seberapa erat service-service itu saling bergantung.

Apa yang sebenarnya dipertaruhkan

Monorepo berarti semua service yang saling terkait erat hidup dalam satu repository git. Polyrepo berarti tiap service punya repository sendiri. Ini kedengarannya remeh, tapi sebenarnya mengubah cara code review, versioning, dan onboarding developer baru berjalan.

Di monorepo, satu pull request bisa mengubah backend dan frontend sekaligus, direview dalam satu konteks, dan di-merge sebagai satu unit yang konsisten. Tapi begitu jumlah service bertambah, repo ini bisa jadi berat: clone melambat, CI harus pintar mendeteksi bagian yang berubah supaya tidak menjalankan seluruh test suite tiap kali, dan permission per-tim jadi lebih rumit kalau ada kontributor eksternal.

Di polyrepo, tiap repo kecil dan fokus — tim yang memegang satu service bisa punya standar coding dan cadence rilis sendiri tanpa mengganggu tim lain. Tapi begitu ada perubahan yang menyentuh dua service sekaligus, misalnya kontrak API antara backend dan frontend, koordinasinya jadi dua PR di dua repo dengan risiko salah satu ketinggalan versi.

Kapan monorepo lebih masuk akal

Untuk tim kecil-menengah yang service-service-nya saling bergantung erat dan biasanya dikembangkan bersamaan — misalnya backend dan frontend dari aplikasi yang sama — monorepo cenderung lebih hemat energi. Satu docker-compose.yml bisa menghidupkan semua service sekaligus untuk development lokal, tanpa perlu mengelola versioning package internal hanya untuk berbagi type antar service. Contoh struktur monorepo yang sering saya pakai:

/app          -> Laravel backend
/resources/js -> Vue frontend (dibundle Vite, disajikan Laravel)
/services/worker -> service kecil terpisah, dipanggil via queue
/docker        -> Dockerfile & compose per environment

Kalau frontend memang disajikan oleh backend yang sama, monorepo hampir selalu lebih masuk akal — memisahkannya jadi dua repo hanya menambah friksi karena keduanya selalu dirilis bersamaan.

Kapan polyrepo lebih masuk akal

Polyrepo jadi lebih menarik ketika service-service itu benar-benar independen — punya siklus rilis sendiri, dipegang oleh tim yang berbeda, atau ditulis dalam stack yang berbeda sama sekali. Sebagai ilustrasi, kalau backend inti pakai Laravel/PHP tapi ada service AI/LLM terpisah dengan stack Python, memisahkannya jadi repo sendiri biasanya lebih rapi: dependency management-nya beda dunia, dan siklus deploy-nya sering tidak sinkron dengan backend utama.

Polyrepo juga lebih cocok kalau salah satu service perlu dibuka aksesnya ke pihak ketiga tanpa memberi akses ke seluruh kode internal — di sini pemisahan repo bukan sekadar soal tooling, tapi soal batas kepercayaan yang jelas.

Satu hal yang sering diabaikan: polyrepo menuntut disiplin versioning lebih ketat. Kalau service A memanggil API service B, harus ada kontrak yang jelas — semantic versioning pada API, dokumentasi endpoint yang update, dan idealnya automated contract test.

Pendekatan praktis untuk tim kecil-menengah

Aturan praktis yang saya pakai: mulai dari monorepo selama tim masih kecil dan service masih sedikit, karena overhead koordinasinya jauh lebih rendah. Pecah jadi repo terpisah begitu ada sinyal konkret — bukan karena "nanti kalau besar pasti butuh", tapi karena sudah ada kebutuhan nyata seperti stack teknologi yang beda total, tim yang benar-benar terpisah dengan cadence rilis sendiri, atau kebutuhan membuka akses ke pihak luar.

Beberapa hal yang membantu apa pun pendekatan yang dipilih:

  • Dokumentasikan kontrak antar service (API, event, shared type) di satu tempat yang mudah ditemukan, terlepas dari jumlah repo.
  • Kalau pakai monorepo, investasikan waktu di CI yang selektif — hanya build/test bagian yang benar-benar berubah.
  • Kalau pakai polyrepo, siapkan automated test untuk kontrak antar service sejak awal, jangan menunggu sampai ada insiden karena versi tidak sinkron.
  • Review ulang keputusan ini secara berkala — struktur yang cocok untuk tim kecil belum tentu cocok saat tim bertambah besar, dan memecah repo terlalu dini juga bisa jadi beban yang tidak perlu.

Takeaway singkat: monorepo dan polyrepo bukan keputusan ideologis, tapi keputusan operasional yang harus mengikuti bentuk tim dan hubungan antar service. Untuk tim kecil-menengah, mulai sederhana dengan monorepo, dan pecah repo hanya ketika ada alasan konkret — bukan karena terlihat lebih "enterprise".