## TL;DR
Docker layer caching in Actions works by storing build cache in the GitHub cache service or a registry, then importing it on the next run. The registry-backed cache is usually the better choice: bigger, more reliable, and scoped per branch. Expect big wins on rebuilds with small changes and almost nothing on builds where every layer changes.

## The query
```text
Docker layer caching with GitHub Actions: setup guide
```

## Use this when
- Docker builds in CI take a long time
- Choosing between cache backends for buildx
- Cache hit rates are low and you want to improve them
- Setting up CI for a containerized service

## Not for when
- Caching non-Docker dependencies (use the cache action directly)
- Local development build speed
- Registry push/pull performance

## Steps

### Step 1: Pick the cache backend
Two main options: the GitHub cache service (simple, size-limited, evicted aggressively) or a registry cache (stored as image layers in your registry, larger and more durable). For serious Docker builds, the registry cache wins; for small images the GitHub cache is fine.
Expected output: a backend choice matched to image size and build frequency.

### Step 2: Configure buildx with cache-to and cache-from
Set up the build step to export cache on every main-branch build and import it on all builds. Scope the cache by branch or target so feature branches benefit from main's cache without polluting it.
Expected output: builds on main populate the cache; PR builds consume it.

### Step 3: Order the Dockerfile for cache hits
Put the least-frequently-changing layers first: base image, system dependencies, language dependencies, then application code last. Every layer after a changed layer rebuilds, so code goes last, always.
Expected output: typical code-change builds reuse most layers and finish in a fraction of the full build time.

### Step 4: Verify hit rates on real builds
Watch a few builds: which steps say CACHED vs rebuild. If hit rates are low, the Dockerfile order or the cache scope is wrong, not the mechanism. Tune until the common case (code change, same deps) is mostly cached.
Expected output: the common-case build is fast; full rebuilds happen only when dependencies change.

### Step 5: Set cache hygiene
Registry caches grow forever; prune old cache entries periodically. GitHub cache entries expire automatically but count against the repo quota. Either way, monitor size and evict what you do not need.
Expected output: cache storage stable over time, not growing unboundedly.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_oFPwizjQQ99L0dEwJ7sEtQ
