GitHub Actions vs GitLab CI untuk backend, web, dan mobile
Perbandingan GitHub Actions dan GitLab CI untuk monorepo: penyiapan runner, penanganan rahasia, caching, dan pola pipeline praktis untuk backend, web, dan mobile.

Kesulitan yang umum di CI multi-aplikasi
Saat satu repo membangun backend, aplikasi web, dan aplikasi mobile, CI berhenti menjadi sekadar "jalanin tes". Ia jadi pengatur lalu lintas untuk toolchain berbeda, waktu build berbeda, dan aturan rilis yang berbeda.
Masalah paling umum sederhana: satu perubahan kecil memicu terlalu banyak pekerjaan. Edit dokumentasi memicu signing iOS, atau tweak backend memaksa rebuild web penuh, dan tiba‑tiba setiap merge terasa lambat dan berisiko.
Dalam setup multi-aplikasi, beberapa masalah muncul cepat:
- Runner drift: versi SDK berbeda antar mesin, sehingga build berperilaku berbeda di CI dan lokal.
- Rahasia tersebar: API key, sertifikat signing, dan kredensial toko diduplikasi di job dan environment.
- Kebingungan cache: kunci cache yang salah membuat build usang, tetapi tanpa cache semua menjadi sangat lambat.
- Aturan rilis bercampur: backend ingin deploy sering, sementara rilis mobile digarisbawahi dan butuh pemeriksaan ekstra.
- Keterbacaan pipeline: konfigurasi tumbuh jadi tembok job yang tak ada yang mau sentuh.
Itu sebabnya pilihan antara GitHub Actions dan GitLab CI lebih penting di monorepo daripada proyek satu-aplikasi. Anda butuh cara jelas untuk membagi pekerjaan berdasarkan path, berbagi artifact dengan aman, dan mencegah job paralel saling menginjak.
Perbandingan praktis masuk ke empat hal: penyiapan dan penskalaan runner, penyimpanan dan pembatasan rahasia, caching dan artifacts, serta seberapa mudah mengekspresikan "hanya bangun apa yang berubah" tanpa mengubah pipeline jadi sup aturan yang rapuh.
Ini soal keandalan dan pemeliharaan sehari-hari, bukan platform mana yang punya lebih banyak integrasi atau UI yang lebih enak. Ini juga bukan pengganti keputusan tentang tool build Anda (Gradle, Xcode, Docker, dan sebagainya). Ini membantu memilih CI yang membuat struktur bersih lebih mudah dipertahankan.
Struktur GitHub Actions dan GitLab CI
Perbedaan terbesar adalah bagaimana tiap platform mengorganisir pipeline dan reuse, dan itu mulai penting saat backend, web, dan mobile berbagi repo yang sama.
GitHub Actions menyimpan automasi di file YAML di bawah .github/workflows/. Workflow dipicu oleh event seperti push, pull request, schedule, atau run manual. GitLab CI berpusat pada .gitlab-ci.yml di root repo, dengan file yang bisa di-include, dan pipeline biasanya berjalan pada push, merge request, schedule, dan job manual.
GitLab dibangun di sekitar stages. Anda mendefinisikan stage (build, test, deploy), lalu menetapkan job ke stage yang berjalan berurutan. GitHub Actions dibangun di sekitar workflow yang berisi job. Job berjalan paralel secara default, dan Anda menambahkan dependensi saat sesuatu harus menunggu.
Untuk menjalankan logika yang sama ke banyak target, matrix build GitHub cocok (iOS vs Android, beberapa versi Node). GitLab bisa melakukan fan‑out serupa dengan parallel job dan variables, tapi sering Anda perlu menyambung lebih banyak bagian sendiri.
Reuse juga terlihat berbeda. Di GitHub, tim biasanya memakai reusable workflows dan composite actions. Di GitLab, reuse sering datang dari include, template bersama, dan YAML anchors/extends.
Persetujuan dan environment terlindungi juga berbeda. GitHub sering memakai protected environments dengan reviewer yang diperlukan dan secrets environment sehingga deploy produksi berhenti sampai disetujui. GitLab biasanya mengombinasikan cabang/tag terlindungi, environment terlindungi, dan job manual agar hanya peran tertentu yang bisa menjalankan deploy.
Penyiapan runner dan eksekusi job
Penyiapan runner adalah tempat kedua platform mulai terasa berbeda dalam penggunaan sehari-hari. Keduanya bisa menjalankan job di hosted runners (Anda tidak mengelola mesin) atau self-hosted runners (Anda memiliki mesin, update, dan keamanannya). Hosted runner lebih mudah untuk mulai; self-hosted sering diperlukan untuk kecepatan, tool khusus, atau akses ke jaringan privat.
Pembagian praktis di banyak tim adalah runner Linux untuk backend dan web, dan runner macOS hanya saat Anda harus membangun iOS. Android bisa dijalankan di Linux, tapi berat, jadi ukuran runner dan ruang disk penting.
Hosted vs self-hosted: apa yang Anda kelola
Hosted runner cocok saat Anda ingin setup yang dapat diprediksi tanpa pemeliharaan. Self-hosted masuk akal saat Anda butuh versi Java/Xcode spesifik, cache yang lebih cepat, atau akses jaringan internal.
Jika memilih self-hosted, definisikan peran runner sejak awal. Kebanyakan repo baik‑baik saja dengan set kecil: runner Linux umum untuk backend/web, runner Linux lebih bertenaga untuk Android, runner macOS untuk packaging dan signing iOS, dan runner terpisah untuk job deploy dengan izin lebih ketat.
Memilih runner yang tepat per job
Kedua sistem memungkinkan menarget runner (labels di GitHub, tags di GitLab). Jaga penamaan terkait beban kerja, seperti linux-docker, android, atau macos-xcode15.
Isolasi adalah sumber banyak build flaky. File sisa, cache bersama yang korup, atau tools yang diinstal "manual" di self-hosted bisa menciptakan kegagalan acak. Workspace bersih, versi tool yang dipin, dan pembersihan runner terjadwal biasanya cepat memberi keuntungan.
Kapabilitas dan izin adalah titik sakit berulang, terutama dengan ketersediaan dan biaya macOS. Default yang baik: runner build bisa membangun, runner deploy bisa deploy, dan kredensial produksi berada pada sekumpulan job sekecil mungkin.
Rahasia dan variabel environment
Rahasia adalah area di mana pipeline multi-aplikasi menjadi berisiko. Prinsip dasarnya mirip (simpan rahasia di platform, suntikkan saat runtime), tapi pembatasan terasa berbeda.
GitHub Actions biasanya memberikan scope rahasia di level repository dan organisasi, dengan lapisan Environment tambahan. Lapisan Environment berguna ketika produksi butuh gate manual dan sekumpulan nilai terpisah dari staging.
GitLab CI menggunakan CI/CD variables di level project, group, atau instance. Ia juga mendukung variabel yang di-scope ke environment, plus proteksi seperti "protected" (hanya tersedia pada cabang/tag terlindungi) dan "masked" (disembunyikan di log). Kontrol ini membantu saat satu monorepo melayani banyak tim.
Mode kegagalan utama adalah eksposur tak sengaja: output debug, perintah yang gagal yang mencetak variabel, atau artifact yang tak sengaja menyertakan file konfigurasi. Anggap log dan artifact bisa dibagikan secara default.
Dalam pipeline backend + web + mobile, rahasia biasanya mencakup kredensial cloud, URL database dan API pihak ketiga, material signing (sertifikat/profil iOS, keystore Android dan password), token registry (npm, Maven, CocoaPods), dan token otomasi (email/SMS provider, chat bot).
Untuk beberapa environment (dev, staging, prod), jaga penamaan konsisten dan tukar nilai berdasar scope environment alih‑alih menyalin job. Itu membuat rotasi dan kontrol akses lebih mudah.
Beberapa aturan mencegah sebagian besar insiden:
- Utamakan kredensial jangka pendek (mis. OIDC ke provider cloud bila tersedia) atas kunci jangka panjang.
- Gunakan prinsip least privilege: identitas deploy terpisah untuk backend, web, dan mobile.
- Masking rahasia dan hindari mencetak variabel environment, bahkan pada kegagalan.
- Batasi rahasia produksi pada cabang/tag terlindungi dan reviewer yang diperlukan.
- Jangan pernah menyimpan rahasia dalam artifact build, bahkan sementara.
Contoh sederhana berdampak tinggi: job mobile hanya menerima rahasia signing pada rilis ber‑tag, sementara job deploy backend dapat menggunakan deploy token terbatas pada merge ke main. Perubahan itu sendiri mengurangi blast radius jika ada job yang salah konfigurasi.
Caching dan artifacts untuk mempercepat build
Kebanyakan pipeline lambat karena satu alasan membosankan: mereka mengunduh dan membangun hal yang sama berulang kali. Caching menghindari pekerjaan berulang. Artifacts menyelesaikan masalah berbeda: menyimpan output persis dari run tertentu.
Apa yang di-cache bergantung pada apa yang Anda bangun. Backend mendapat manfaat dari cache dependency dan compiler (mis. cache module Go). Build web mendapat manfaat dari cache package manager dan tool build. Mobile sering butuh Gradle plus cache Android SDK di Linux, dan CocoaPods atau Swift Package Manager di macOS. Hati‑hati dengan caching output build iOS yang agresif (seperti DerivedData) kecuali Anda mengerti trade‑off‑nya.
Kedua platform mengikuti pola dasar yang sama: restore cache di awal job, simpan cache yang diperbarui di akhir. Perbedaan sehari‑hari adalah kontrol. GitLab membuat perilaku cache dan artifact eksplisit di satu file, termasuk expiration. GitHub Actions sering bergantung pada action terpisah untuk caching, yang fleksibel tapi lebih mudah salah konfigurasi.
Kunci cache lebih penting di monorepo. Kunci yang baik berubah ketika input berubah, dan tetap stabil jika tidak. Lockfile (go.sum, pnpm-lock.yaml, yarn.lock, dan sejenisnya) harus menjadi pendorong kunci. Juga membantu memasukkan hash folder aplikasi spesifik yang Anda bangun alih‑alih seluruh repo, dan menjaga cache terpisah per aplikasi agar satu perubahan tidak membatalkan semuanya.
Gunakan artifacts untuk deliverable yang ingin Anda simpan dari run itu: bundle rilis, APK/IPA, laporan tes, file coverage, dan metadata build. Cache adalah percepatan best‑effort; artifacts adalah catatan.
Jika build masih lambat, periksa cache terlalu besar, kunci yang berubah tiap run (timestamp dan commit SHA umum terjadi), dan output build yang di-cache yang tidak bisa dipakai ulang di antara runner.
Kecocokan monorepo: banyak pipeline tanpa kekacauan
Monorepo menjadi berantakan saat setiap push memicu tes backend, build web, dan signing mobile, walaupun Anda hanya mengubah README. Pola bersih adalah: deteksi yang berubah, jalankan hanya job yang relevan.
Di GitHub Actions, ini sering berarti workflow terpisah per aplikasi dengan path filters sehingga setiap workflow berjalan hanya saat file di areanya berubah. Di GitLab CI, ini sering berarti satu file pipeline menggunakan rules:changes (atau child pipelines) untuk membuat atau melewatkan grup job berdasarkan path.
Paket bersama adalah tempat kepercayaan mudah rusak. Jika packages/auth berubah, backend dan web mungkin perlu dibangun ulang meski folder mereka tak berubah. Perlakukan path bersama sebagai pemicu bagi banyak pipeline dan jaga batas dependensi tetap jelas.
Peta trigger sederhana yang membuat kejutan minimal:
- Job backend berjalan saat ada perubahan di
backend/**ataupackages/**. - Job web berjalan saat ada perubahan di
web/**ataupackages/**. - Job mobile berjalan saat ada perubahan di
mobile/**ataupackages/**. - Perubahan hanya dokumen menjalankan cek cepat (formatting, spellcheck).
Parallelize apa yang aman (unit test, linting, build web). Serialisasikan apa yang harus dikontrol (deploy, rilis ke app store). Baik needs di GitLab maupun dependency job di GitHub membantu Anda menjalankan cek cepat lebih awal dan menghentikan sisanya saat gagal.
Jaga signing mobile terisolasi dari CI sehari‑hari. Taruh kunci signing di environment khusus dengan persetujuan manual, dan jalankan signing hanya pada rilis ber‑tag atau cabang terlindungi. Pull request normal masih bisa membangun aplikasi tanpa signing untuk validasi tanpa mengekspos kredensial sensitif.
Langkah demi langkah: pipeline bersih untuk backend, web, dan mobile
Pipeline multi‑aplikasi yang bersih dimulai dengan penamaan yang memperjelas maksud. Pilih satu pola dan konsisten sehingga orang bisa melihat log dan tahu apa yang dijalankan.
Satu skema yang mudah dibaca:
- Pipelines:
pr-checks,main-build,release - Environments:
dev,staging,prod - Artifacts:
backend-api,web-bundle,mobile-debug,mobile-release
Dari situ, jaga job kecil dan promosikan hanya yang lulus pemeriksaan awal:
-
PR checks (setiap pull request): jalankan tes cepat dan lint hanya untuk aplikasi yang berubah. Untuk backend, bangun artifact yang bisa dideploy (image container atau server bundle) dan simpan supaya langkah selanjutnya tidak membangunnya lagi.
-
Web build (PR + main): bangun web app menjadi bundle statis. Pada PR, simpan output sebagai artifact (atau deploy ke preview environment jika ada). Pada main, hasilkan bundle versioned untuk
devataustaging. -
Mobile debug builds (PR saja): bangun APK/IPA debug. Jangan sign untuk release. Tujuannya umpan balik cepat dan file yang bisa diinstal tester.
-
Release builds (hanya tag): saat tag seperti
v1.4.0didorong, jalankan full build backend dan web plus signed mobile release builds. Hasilkan output siap‑toko dan simpan catatan rilis bersama artifacts. -
Persetujuan manual: tempatkan persetujuan antara
stagingdanprod, bukan sebelum tes dasar. Developer bisa memicu build, tapi hanya peran yang disetujui yang boleh deploy ke produksi dan mengakses rahasia produksi.
Kesalahan umum yang membuang waktu
Tim sering kehilangan minggu karena kebiasaan workflow yang diam‑diam menciptakan build flaky.
Satu jebakan adalah terlalu bergantung pada runner bersama. Saat banyak proyek bersaing pada pool yang sama, Anda dapat mengalami timeout acak, job lambat, dan build mobile yang gagal hanya pada jam puncak. Jika backend, web, dan mobile penting, pisahkan job berat ke runner khusus (atau setidaknya antrean terpisah) dan tetapkan limit resource secara eksplisit.
Rahasia adalah sumber waktu terbuang lainnya. Kunci dan sertifikat signing mobile mudah salah urus. Kesalahan umum adalah menyimpannya terlalu luas (tersedia ke setiap cabang dan job) atau membocorkannya melalui log yang verbose. Batasi material signing ke cabang/tag terlindungi, dan hindari langkah yang mencetak nilai rahasia (bahkan base64).
Caching bisa berbalik merugikan saat tim meng-cache direktori besar atau mencampur cache dan artifact. Cache hanya input yang stabil. Simpan output yang Anda butuhkan nanti sebagai artifact.
Akhirnya, di monorepo, memicu setiap pipeline pada setiap perubahan menghabiskan menit dan kesabaran. Jika seseorang mengubah README dan Anda membangun ulang iOS, Android, backend, dan web, orang berhenti percaya pada CI.
Checklist cepat yang membantu:
- Gunakan aturan berbasis path sehingga hanya aplikasi terdampak yang berjalan.
- Pisahkan job test dari job deploy.
- Jaga kunci signing dibatasi pada workflow rilis.
- Cache input yang kecil dan stabil, bukan seluruh folder build.
- Rencanakan kapasitas runner yang dapat diprediksi untuk build mobile yang berat.
Cek cepat sebelum Anda memilih satu platform
Sebelum memilih, lakukan beberapa cek yang mencerminkan cara kerja Anda sebenarnya. Ini mencegah memilih alat yang terasa baik untuk satu aplikasi tapi menyusahkan saat menambahkan mobile, banyak environment, dan rilis.
Fokus pada:
- Rencana runner: hosted, self-hosted, atau campuran. Build mobile sering mendorong tim ke campuran karena iOS butuh macOS.
- Rencana rahasia: di mana rahasia disimpan, siapa yang bisa membacanya, dan bagaimana rotasi bekerja. Produksi harus lebih ketat daripada staging.
- Rencana cache: apa yang Anda cache, di mana disimpan, dan bagaimana kunci dibentuk. Jika kunci berubah setiap commit, Anda membayar biaya tanpa percepatan.
- Rencana monorepo: filter path dan cara bersih berbagi langkah umum (lint, test) tanpa copy‑paste.
- Rencana rilis: tag, persetujuan, dan pemisahan environment. Jelaskan siapa yang bisa mempromosikan ke produksi dan bukti apa yang diperlukan.
Uji jawaban itu dengan skenario kecil. Di monorepo dengan backend Go, web Vue, dan dua aplikasi mobile: perubahan hanya dokumen seharusnya hampir tidak melakukan apa‑apa; perubahan backend harus menjalankan tes backend dan membuat artifact API; perubahan UI mobile harus membangun hanya Android dan iOS.
Jika Anda tidak bisa menjelaskan alur itu di satu halaman (trigger, cache, rahasia, persetujuan), jalankan pilot satu minggu di kedua platform dengan repo yang sama. Pilih yang terasa membosankan dan dapat diprediksi.
Contoh: alur build dan rilis monorepo yang realistis
Bayangkan satu repo dengan tiga folder: backend/ (Go), web/ (Vue), dan mobile/ (iOS dan Android).
Sehari‑hari, Anda ingin umpan balik cepat. Saat rilis, Anda ingin full build, signing, dan langkah publish.
Pisahan praktis:
- Feature branches: jalankan lint + unit test untuk bagian yang berubah, bangun backend dan web, dan opsional jalankan Android debug build. Lewatkan iOS kecuali benar‑benar perlu.
- Release tags: jalankan semuanya, buat artifact versioned, sign mobile apps, dan dorong image/binary ke storage rilis Anda.
Pilihan runner berubah saat mobile terlibat. Build Go dan Vue cocok di Linux hampir di mana saja. iOS membutuhkan runner macOS, yang sering jadi faktor penentu. Jika tim ingin kontrol penuh mesin build, GitLab CI dengan self-hosted runner bisa lebih mudah dijalankan sebagai fleet. Jika Anda lebih suka pekerjaan ops lebih sedikit dan setup cepat, hosted runner GitHub nyaman, tapi menit macOS dan ketersediaannya menjadi bagian dari perencanaan.
Caching adalah tempat waktu nyata dihemat, tapi cache terbaik berbeda per aplikasi. Untuk Go, cache unduhan module dan cache build. Untuk Vue, cache store package manager dan rebuild hanya saat lockfile berubah. Untuk mobile, cache Gradle dan Android SDK di Linux; cache CocoaPods atau Swift Package Manager di macOS, dan harapkan cache lebih besar serta lebih sering invalidasi.
Aturan keputusan yang tahan banting: jika kode Anda sudah dihosting di satu platform, mulailah dari situ. Beralih hanya jika runner (terutama macOS), izin, atau kepatuhan memaksa.
Langkah berikutnya: pilih, standarkan, dan otomatisasi dengan aman
Pilih alat yang cocok dengan tempat kode dan orang Anda sudah berada. Sebagian besar waktu, perbedaan muncul di gesekan sehari‑hari: review, izin, dan seberapa cepat seseorang bisa mendiagnosis build yang rusak.
Mulai sederhana: satu pipeline per aplikasi (backend, web, mobile). Setelah stabil, tarik langkah bersama ke template reuse sehingga mengurangi copy‑paste tanpa mengaburkan kepemilikan.
Tuliskan ruang lingkup rahasia seperti Anda menuliskan siapa yang punya kunci kantor. Rahasia produksi tidak boleh bisa dibaca oleh setiap cabang. Set pengingat rotasi (kuartalan lebih baik dari tidak pernah), dan sepakati cara revokasi darurat.
Jika Anda membangun dengan generator no‑code yang menghasilkan kode sumber nyata, perlakukan regenerasi/ekspor sebagai langkah CI kelas‑satu. Misalnya, AppMaster (appmaster.io) menghasilkan backend Go, web Vue3, dan mobile Kotlin/SwiftUI, sehingga pipeline Anda bisa meregenerasi kode saat perubahan, lalu hanya membangun target yang terpengaruh.
Setelah Anda punya alur yang dipercaya tim, jadikan itu default untuk repo baru dan biarkan tetap membosankan: trigger jelas, runner dapat diprediksi, rahasia ketat, dan rilis hanya berjalan saat Anda benar‑benar bermaksud.
FAQ
Secara default pilih platform tempat kode dan tim Anda sudah berada, lalu hanya pindah jika runner (terutama macOS), izin, atau kepatuhan memaksa Anda. Biaya harian biasanya muncul pada ketersediaan runner, pengaturan ruang lingkup rahasia, dan seberapa mudah menyatakan “hanya bangun apa yang berubah” tanpa aturan yang rapuh.
GitHub Actions terasa lebih sederhana untuk setup cepat dan build matriks, dengan workflow yang dibagi ke beberapa file YAML. GitLab CI cenderung lebih terpusat dan berorientasi stage, yang bisa lebih mudah untuk menalar ketika pipeline tumbuh dan Anda ingin satu tempat untuk mengontrol cache, artifact, dan urutan job.
Anggap macOS sebagai sumber daya langka: gunakan hanya ketika benar-benar perlu packaging atau signing iOS. Baseline yang umum adalah runner Linux untuk backend dan web, runner Linux lebih besar untuk Android, runner macOS khusus untuk job iOS, dan satu runner deploy terpisah dengan izin lebih ketat.
Runner drift terjadi saat job sama berperilaku berbeda karena SDK dan tools berbeda antar mesin. Perbaiki dengan mem-pin versi tools, hindari instalasi manual di self-hosted runner, gunakan workspace bersih, dan bersihkan atau bangun ulang image runner secara berkala agar perbedaan tidak menumpuk.
Buat rahasia hanya tersedia untuk job terkecil yang membutuhkannya, dan jaga rahasia produksi di belakang cabang/tag yang dilindungi plus persetujuan. Untuk mobile, default paling aman adalah menyuntikkan material signing hanya pada rilis ber-tag, sementara pull request membangun artifact debug tanpa signing untuk validasi.
Gunakan cache untuk mempercepat pekerjaan berulang, dan artifacts untuk menyimpan output tepat dari sebuah run. Cache bersifat best-effort dan bisa berubah, sedangkan artifact adalah deliverable yang ingin Anda simpan—misalnya bundle rilis, laporan test, atau APK/IPA yang bisa ditelusuri ke run tertentu.
Bangun kunci cache berdasarkan input yang stabil seperti lockfile, dan skopkan ke bagian repo yang Anda bangun agar perubahan tidak terkait tidak membatalkan semuanya. Hindari kunci yang berubah tiap run (timestamp atau SHA penuh), dan pisahkan cache per aplikasi agar backend, web, dan mobile tidak saling mengganggu.
Gunakan aturan berbasis path sehingga dokumen atau folder tak terkait tidak memicu job mahal. Perlakukan paket bersama sebagai trigger eksplisit untuk aplikasi yang bergantung padanya; jika folder bersama berubah, wajar bila beberapa target dibangun ulang, tapi biarkan pemicu itu sengaja dan dapat diprediksi.
Jaga kunci signing dan kredensial toko di luar run CI sehari‑hari dengan mengaturnya di balik tag, cabang yang dilindungi, dan persetujuan. Untuk pull request, bangun varian debug tanpa signing release sehingga Anda tetap mendapat umpan balik cepat tanpa mengekspos kredensial berisiko tinggi.
Bisa, tapi perlakukan proses regenerasi sebagai langkah kelas-satu dengan input dan output yang jelas agar mudah di-cache dan dijalankan ulang secara prediktabel. Jika Anda memakai alat seperti AppMaster (appmaster.io) yang menghasilkan kode sumber nyata, regenerasi pada perubahan relevan lalu bangun hanya target yang terpengaruh berdasarkan perubahan setelah regenerasi.


