Caching Strategies — Build, Test, Deploy Cache#
"Cache hit %0 = 'biz yeni başlıyoruz' demek. Production CI'da cache hit %80+ olmalı. Cache stratejisi, 30 dk pipeline'ı 3 dk'ya indirir."
Bu rehber CI/CD'de farklı cache katmanlarını — dependency, build, Docker layer, test result — strateji + somut config ile anlatır.
🪜 Cache Katmanları#
[Source Code]
│
▼
[1. Dependency Cache] ← npm, pip, go, cargo, maven
│
▼
[2. Build Cache] ← compile output (target/, dist/, .next/)
│
▼
[3. Docker Layer Cache] ← BuildKit, registry cache
│
▼
[4. Test Cache] ← Jest, Go test cache, etc.
│
▼
[5. Artifact Cache] ← release artifact, internal package
🔧 1️⃣ Dependency Cache#
Node.js (npm / yarn / pnpm)#
- uses: actions/setup-node@<VERSION>
with:
node-version: '22'
cache: 'npm' # otomatik
# Veya:
# cache: 'yarn'
# cache: 'pnpm'
Manuel:
- uses: actions/cache@<VERSION>
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
Python (pip / poetry / uv)#
Go#
Manuel:
- uses: actions/cache@<VERSION>
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
Rust (Cargo)#
Manuel:
- uses: actions/cache@<VERSION>
with:
path: |
~/.cargo/registry
~/.cargo/git
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
Maven / Gradle#
- uses: actions/cache@<VERSION>
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
🏗️ 2️⃣ Build Cache#
Webpack / Next.js#
- uses: actions/cache@<VERSION>
with:
path: |
.next/cache
~/.cache/webpack
key: ${{ runner.os }}-build-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('src/**') }}
restore-keys: |
${{ runner.os }}-build-${{ hashFiles('**/package-lock.json') }}-
${{ runner.os }}-build-
Turborepo#
- uses: actions/cache@<VERSION>
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-
🔑 Turborepo remote cache S3'te → tüm developer + CI paylaşır.
Nx#
- run: npx nx affected --target=test --base=main
env:
NX_CACHE_DIRECTORY: ${{ github.workspace }}/.nx
Bazel#
- uses: actions/cache@<VERSION>
with:
path: |
~/.cache/bazel
~/.cache/bazelisk
key: ${{ runner.os }}-bazel-${{ hashFiles('WORKSPACE', '**/BUILD.bazel') }}
🐳 3️⃣ Docker Layer Cache (BuildKit)#
GitHub Actions cache backend#
- uses: docker/setup-buildx-action@<VERSION>
- uses: docker/build-push-action@<VERSION>
with:
context: .
push: true
tags: <REGISTRY>/<APP>:${{ github.sha }}
cache-from: type=gha,scope=${{ github.workflow }}
cache-to: type=gha,scope=${{ github.workflow }},mode=max
Registry-backed cache (paylaşımlı)#
- uses: docker/build-push-action@<VERSION>
with:
cache-from: type=registry,ref=<REGISTRY>/<APP>:cache
cache-to: type=registry,ref=<REGISTRY>/<APP>:cache,mode=max
→ Birden fazla CI / dev makinesi aynı cache'i paylaşır.
Inline cache#
- uses: docker/build-push-action@<VERSION>
with:
push: true
tags: <REGISTRY>/<APP>:latest
cache-from: type=registry,ref=<REGISTRY>/<APP>:latest
cache-to: type=inline # cache image'in içinde
→ Image'in içine cache embed; basit ama image boyutu artar.
BuildKit cache mount (Dockerfile içinde)#
FROM rust:1.75 AS builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
# Cargo target + registry cache
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo fetch
COPY . .
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo build --release && \
cp target/release/myapp /myapp
→ İlk build 5 dk, ikinci build (kod değişti) 30 saniye.
🧪 4️⃣ Test Cache#
Jest (built-in)#
- uses: actions/cache@<VERSION>
with:
path: /tmp/jest_rs
key: ${{ runner.os }}-jest-${{ github.sha }}
restore-keys: |
${{ runner.os }}-jest-
Go test cache#
- run: go test -count=1 ./...
# -count=1 cache disable; production için sadece etkilenen path'i test
Pytest cache#
- uses: actions/cache@<VERSION>
with:
path: .pytest_cache
key: ${{ runner.os }}-pytest-${{ hashFiles('**/conftest.py', '**/pytest.ini') }}
Selective test (test cache değil ama hızlandırır)#
# Nx
npx nx affected --target=test --base=main
# Turborepo
turbo run test --filter=...[origin/main]
# Bazel
bazel test --test_strategy=remote //... --target=//apps/payments:test
🚀 5️⃣ Artifact Cache#
Internal package registry (Verdaccio, Nexus, Artifactory)#
→ npmjs.org down olsa bile build çalışır + daha hızlı.
Container registry mirror#
# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirror.<INTERNAL>.com"]
→ Docker Hub rate limit + supply chain attack koruması.
📐 Cache Key Strategy#
İyi key#
- OS dahil (linux ≠ macos cache) - Version dahil (Node 18 ≠ 22) - Lockfile hash → invalidasyon doğruKötü key#
Restore-keys (fallback)#
key: ${{ runner.os }}-deps-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-deps- # exact match yoksa partial
📊 Cache Effectiveness Ölçümü#
Cache hit rate#
# GitHub Actions log
"Cache restored from key: ..." # hit
"Cache not found for input keys: ..." # miss
Hedef#
- Dependency cache: %90+ hit
- Docker layer cache: %70+ hit
- Build cache: %50+ hit
Quarterly review#
- En sık miss eden cache → key strategy gözden geçir
- Cache size trend (10+ GB ise temizle)
- TTL vs invalidation rate
🚫 Anti-Pattern Tablosu#
| Anti-pattern | Niye kötü | Doğru |
|---|---|---|
| Cache yok | Her build 5+ dk dep install | cache: true her dil |
| Cache key static | Asla invalidate olmaz | hashFiles(...) |
| Restore-keys yok | İlk build cache miss | Fallback partial match |
| OS bağımsız key | Cross-OS contamination | ${{ runner.os }} dahil |
| Branch başına cache yok | Main + branch çakışması | ${{ github.ref_name }} ile |
BuildKit cache mode min | Sadece final layer | mode=max (tüm intermediate) |
| Cache size sonsuz | 50+ GB artifact birikir | Periodic cleanup + size limit |
| Sensitive data cache'de | Compromise → secret leak | Cache'e secret yazma |
| Multi-arch build cache karışık | amd64 / arm64 birbirine | Per-platform cache |
actions/cache@v1 (eski) | Bug + slow | Latest pinned SHA |
| Test cache prod'da | Stale result | -count=1 veya cache disable |
📋 Cache Strategy Checklist#
[ ] Dependency cache: tüm dil/framework için
[ ] Docker layer cache: BuildKit GHA / registry
[ ] Cache key: OS + version + lockfile hash
[ ] Restore-keys: partial match fallback
[ ] BuildKit cache-to: mode=max
[ ] Cache mount Dockerfile (Cargo, Go target)
[ ] Internal package registry mirror
[ ] Container registry mirror
[ ] Selective testing (Nx / Turbo affected)
[ ] Cache hit rate dashboard
[ ] Quarterly: cache effectiveness review
[ ] Cache size limit + cleanup
[ ] Secret data cache'e girmiyor
[ ] Per-platform multi-arch cache
📚 Referanslar#
- actions/cache — github.com/actions/cache
- BuildKit Cache — docs.docker.com/build/cache
- Turborepo Caching — turbo.build/repo/docs/core-concepts/caching
- Nx Affected — nx.dev
Pipeline-Performance.mdGitHub-Actions-Recipes.mdGitLab-CI-Recipes.md
"Cache 'optional optimization' değil — CI'ın temel disiplini. Cache hit %30'da çalışan ekip, Saturday gece 'pipeline yavaş' postmortem yazar; %90'da çalışan ekip erken gider."