The problem: Docker builds in GitHub Actions were taking 8 minutes every run. The cache layers were being pulled but not used — every step showed "CACHED" in local builds but not in CI.
The fix:
# GitHub Actions workflow — add cache-from and cache-to:
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: my-app:latest
cache-from: type=gha # Pull cache from GitHub Actions cache
cache-to: type=gha,mode=max # Push all layers to cache (not just final)# Also make sure Dockerfile is ordered for cache efficiency:
# WRONG order — code changes invalidate all subsequent layers:
COPY . .
RUN npm install
# RIGHT order — dependencies cached separately from code:
COPY package*.json ./
RUN npm install # ← cached unless package.json changes
COPY . . # ← only this layer rebuilds on code change
RUN npm run buildWhy it happens:
GitHub Actions runners are ephemeral — each run starts on a fresh machine with no local Docker cache. Without cache-from: type=gha, Docker has nothing to compare against and rebuilds everything. The mode=max flag exports intermediate layers too (not just the final image), making subsequent builds much faster.