Strategi Caching GitHub Actions yang Benar-Benar Memangkas Menit CI

Foto oleh Roman Synkevych

Foto oleh Roman Synkevych
Menit CI adalah salah satu biaya yang merayap naik. Pipeline yang dulu empat menit saat repo masih muda menjadi sebelas menit dua tahun kemudian, tidak ada yang ingat kapan itu terjadi, dan tiba-tiba setiap siklus review pull request menyertakan jeda ngopi. Saat saya mengaudit workflow di proyek klien dan aplikasi saya sendiri, tuas terbesar bukan paralelisme atau runner lebih besar — melainkan caching yang dilakukan dengan sengaja, bukan sekadar ikut-ikutan.
Artikel ini membahas tiga lapis cache yang penting di pipeline GitHub Actions pada umumnya — dependency package manager, layer image Docker, dan build cache framework — lengkap dengan konfigurasi persis yang saya jalankan, limit platform yang diam-diam menyabotase setup naif, dan anti-pattern yang terus saya temukan di repo nyata. Sebagian besar tim bisa memangkas 30 sampai 60 persen wall time CI dengan kerja satu sore di sini.
Sebelum mengoptimasi apa pun, pahami dulu aturan platformnya, karena aturan ini membentuk setiap keputusan strategi:
Untuk proyek Node, caching bawaan setup-node mencakup sebagian besar kebutuhan dengan satu baris — ia menghash lockfile Anda dan meng-cache store global package manager. Pakai pendekatan manual actions/cache hanya saat Anda meng-cache lebih dari dependency, misalnya cache build inkremental Next.js:
# 90% of Node projects only need this
- uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm" # also accepts yarn / pnpm
# manual control when you cache more than the package manager
- uses: actions/cache@v4
with:
path: |
~/.npm
.next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
restore-keys: |
nextjs-${{ runner.os }}-${{ hashFiles('package-lock.json') }}-
nextjs-${{ runner.os }}-Fallback restore-keys dua tingkat adalah bagian yang paling sering dilewati orang. Dengannya, perubahan lockfile tetap me-restore cache sebelumnya dan hanya mengunduh delta-nya; tanpanya, setiap bump dependency menjadi npm install dingin. Di aplikasi Next.js ukuran menengah ini bedanya antara step install 40 detik dan 3 menit.
Ukur sebelum dan sesudah: step cache mencatat hit/miss dan key yang di-restore. Saya menambah job summary satu baris yang mencetak status cache, karena rentetan partial miss yang senyap terlihat identik dengan caching yang bekerja kecuali Anda memeriksanya.
Kalau workflow Anda membangun image, lapis ini mengerdilkan semua lapis lain. Secara default, setiap build CI mulai dari nol — tidak ada layer cache di runner yang masih segar. Backend cache GitHub Actions milik BuildKit memperbaikinya dengan dua baris:
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/you/app:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=maxBackend type=gha menyimpan blob layer di layanan cache yang sama dengan dependency Anda, artinya mereka berbagi budget 10 GB. Flag mode=max meng-cache layer perantara dari setiap build stage, bukan hanya image final — inilah yang membuat multi-stage build jadi cepat. Untuk image lebih besar ada opsi kedua yang layak diketahui:
Cache type=gha
Nol infrastruktur, ideal untuk image aplikasi di bawah kira-kira satu gigabyte layer. Terhitung dalam budget 10 GB repo dan eviction 7 hari. Butuh Buildx 0.21+ dan BuildKit 0.20+ karena layanan cache pindah ke API v2 pada April 2025.
Cache type=registry
Mendorong cache sebagai artefak ke container registry Anda dengan dukungan mode=max. Tidak dibatasi kuota Actions, selamat dari aturan 7 hari, bisa dibagi antar repo bahkan ke build lokal. Pilihan saya untuk base image dan apa pun yang dibangun ulang kurang dari harian.
Tiga angka ini menjelaskan hampir semua pipeline misterius-lambat yang pernah saya debug:
| Limit | Nilai | Dampaknya bagi Anda |
|---|---|---|
| Budget cache repo | 10 GB default | Cache layer Docker dengan mode=max bisa mengusir cache dependency Anda. Pantau daftar cache di tab Actions. |
| Eviction karena tidak aktif | 7 hari | Workflow mingguan dan khusus rilis selamanya jalan dingin. Pertimbangkan job pemanas terjadwal atau cache berbasis registry. |
| Panjang key | 512 karakter | Ekspresi hashFiles panjang dengan banyak glob bisa meluber; hash satu file manifest hasil generate saja. |
Jangan pernah meng-cache node_modules langsung dengan key dari lockfile. Itu rusak antar versi Node dan image OS, menutupi script postinstall, dan hematnya lebih kecil daripada meng-cache store npm. Direktori cache milik package manager plus clean install itu lebih cepat sekaligus benar.
Ini urutan yang saya jalankan di setiap repo yang saya ambil alih:
Di repo yang memicu audit ini, total waktu pipeline turun dari 11 menit menjadi sedikit di atas 4: caching dependency dengan restore-keys yang benar menghemat 2 menit, caching layer Docker dengan type=gha menghemat 4, dan cache build Next.js menghemat sisanya. Tidak ada yang butuh infrastruktur baru atau runner berbayar — cukup memahami aturan eviction dan menaruh tipe cache yang tepat di tiap lapis.
Caching adalah salah satu optimasi langka di mana kerjanya terbatas tapi hasilnya berbunga di setiap push. Luangkan satu sore itu. Reviewer Anda, frekuensi deploy Anda, dan tagihan Actions Anda membaik bersamaan.
Sumber dan bacaan lanjutan