Faster Docker Builds: Practical Guide to BuildKit cache, buildx, and image optimization

Slow Docker builds in CI waste developer time and CI minutes. BuildKit (via docker buildx) gives you powerful ways to persist and share build cache across runs and machines — if you use them properly. This guide explains the most useful BuildKit cache features, shows practical Dockerfile and CI examples, and lists the small changes that usually yield the biggest speed wins.

Why this matters

Overview of BuildKit caching

Key cache backends (quick)

Practical CI recipe (buildx + registry cache)

  1. Build and push an image and export cache to the registry at the end of the job:
    docker buildx build --push \
      -t my-registry.example.com/my-app:latest \
      --cache-to type=registry,ref=my-registry.example.com/my-app:cache,mode=max \
      .
    
  2. In subsequent CI runs, import that cache before building:
    docker buildx build \
      -t my-registry.example.com/my-app:latest \
      --cache-from type=registry,ref=my-registry.example.com/my-app:cache \
      --cache-to type=registry,ref=my-registry.example.com/my-app:cache,mode=max \
      --push
    

    This pattern gives CI builds access to previously produced layers and intermediate-stage outputs, saving network time and rebuild work. The registry cache supports parameters like mode (min vs max), compression (gzip/zstd), and OCI media-type options for compatibility. (docs.docker.com)

GitHub Actions example (using docker/build-push-action)

Use cache mounts in your Dockerfile (the single biggest win)**

Multistage builds and layer ordering

Cache modes: min vs max (tradeoffs)

Practical tips and pitfalls

Checklist to get started (copy-paste)

Minimal example pipeline (shell)

# First build (cold): push image and cache
docker buildx build --push -t registry/my-app:latest \
  --cache-to type=registry,ref=registry/my-app:cache,mode=max .

# Next build (warm): import cache to speed up
docker buildx build --push -t registry/my-app:latest \
  --cache-from type=registry,ref=registry/my-app:cache \
  --cache-to type=registry,ref=registry/my-app:cache,mode=max .

Real-world impact

Further reading and references

Closing notes

Start with one small change: add a –mount=type=cache for your package manager and enable cache export/import in CI. That modest change is where most teams see the biggest build-time drop with the least complexity. Once that’s working, experiment with registry vs inline vs gha cache exporters and the mode option to balance cache size and hit-rate for your workflow.