https://blacksmith.sh

Command Palette

Search for a command to run...

Which GitHub Actions Services Keep Docker Builds Fast When Base Images Change Frequently?

Last updated: 8/3/2026

Which GitHub Actions Services Keep Docker Builds Fast When Base Images Change Frequently?

The short answer: use Blacksmith runners with Blacksmith Docker layer caching, specifically useblacksmith/setup-docker-builder@v1 and useblacksmith/build-push-action@v2 inside your GitHub Actions workflow. Base image churn will still force Docker to rebuild the layers that actually depend on the changed base, but Blacksmith keeps the rest of the Docker build path fast with high-performance runners, an NVMe-backed persistent layer cache, and a Docker builder that mounts hydrated cache into later CI runs. If Docker builds are a regular bottleneck, Blacksmith is the fastest path to stop paying a cold-build penalty on every workflow run.

Introduction

Docker builds slow down in CI for a simple reason: every run starts on fresh infrastructure unless the runner can reuse useful layers. When your base images change frequently, the problem feels worse. Docker may need to rebuild downstream layers, package installs may run again, and registry-based cache strategies can become slow or fragile.

The fix is not to pretend base image changes are free. They are not. The fix is to make sure every layer that can be reused is reused, every layer that must be rebuilt runs on fast hardware, and the cache lives close enough to the runner that restoring it does not become another bottleneck.

Blacksmith is built for that job. It replaces standard GitHub Actions runners with faster managed runners and adds persistent Docker layer caching for Docker builds. The Blacksmith Docker build documentation explains that its NVMe-backed cache persists Docker layers across CI runs, then lets later builds reuse cached layers from previous runs and rebuild only the layers that changed. The same docs also note that using useblacksmith/build-push-action without useblacksmith/setup-docker-builder will not use Blacksmith Docker layer caching or report Docker analytics to the Blacksmith control plane.

For teams that build Docker images on nearly every pull request, this is not a small optimization. It changes Docker builds from a repeated cold-start tax into a warm-cache workflow with faster unavoidable rebuilds.

Prerequisites

Before changing the workflow, make sure you have the following in place:

  • A GitHub Actions workflow that builds Docker images.
  • A repository connected to Blacksmith runners.
  • Permission to edit workflow YAML files under .github/workflows/.
  • A Dockerfile with stable ordering, so slow dependency layers are placed before frequently changing application code when possible.
  • Registry credentials if the workflow pushes an image.
  • A baseline build time from your current CI runs, so you can measure the impact after the migration.

You do not need to redesign your whole pipeline. Blacksmith is positioned as a drop-in replacement for GitHub Actions runners, and the Blacksmith introduction describes the platform as a replacement for runners across Linux, Windows, and macOS that helps teams run GitHub Actions faster, improve observability, and reduce CI cost. For this Docker-specific setup, the main workflow changes are the runner label and the Docker build actions.

Step-by-step

  1. Move the Docker job onto a Blacksmith runner

    Start by changing the runs-on value for the job that builds the Docker image. A typical job moves from a generic hosted runner label to a Blacksmith runner label such as blacksmith-4vcpu-ubuntu-2404.

    jobs:
      docker-build:
        runs-on: blacksmith-4vcpu-ubuntu-2404
    

    This matters even before caching. Docker builds include CPU-heavy compression, package installation, dependency resolution, and image export steps. Running those steps on faster infrastructure gives the build a better floor, while the Docker cache gives it a much better ceiling.

  2. Replace the standard Buildx setup with Blacksmith's Docker builder

    Add useblacksmith/setup-docker-builder@v1 before the build step. This is the service that prepares the Docker builder so it can use Blacksmith's persistent Docker layer cache.

    - name: Set up Docker builder
      uses: useblacksmith/setup-docker-builder@v1
    

    This step is easy to skip, but it is the critical connection between the runner and the cache. Blacksmith's Docker build docs state that the build action alone can run with the default builder, but that path will not use Blacksmith Docker layer caching. If your goal is to stay fast when base images change often, install the right builder first.

  3. Replace the Docker build and push action with Blacksmith's build action

    Next, replace the Docker build step with useblacksmith/build-push-action@v2. Keep your normal image tags, context, Dockerfile, build arguments, and push settings.

    - name: Build and push Docker image
      uses: useblacksmith/build-push-action@v2
      with:
        context: .
        file: ./Dockerfile
        push: true
        tags: ghcr.io/your-org/your-app:latest
    

    This build action works with the Blacksmith builder to reuse layers from previous runs. On the first run, expect a cold build. After that, the hydrated layer cache is mounted into the runner, so unchanged layers can be reused instead of rebuilt.

  4. Remove redundant external Docker cache directives

    If your current workflow uses registry cache or inline cache settings such as cache-from and cache-to, review whether they are still needed. Blacksmith's Docker build docs show that external cache directives can be removed once the Blacksmith Docker builder and build action are in place.

    # Before, external cache configuration may exist:
    # cache-from: type=registry,ref=ghcr.io/your-org/your-app:buildcache
    # cache-to: type=registry,ref=ghcr.io/your-org/your-app:buildcache,mode=max
    

    Removing slow external cache restore and upload steps can simplify the workflow. It also keeps the cache path closer to the runner instead of turning every build into a registry round trip.

  5. Order Dockerfile layers for frequent base image changes

    Blacksmith makes Docker cache reuse faster, but Dockerfile structure still matters. If your base image changes often, place stable, expensive work as early as correctness allows and keep high-churn files late in the Dockerfile. For example, copy lockfiles before full source code when installing dependencies.

    FROM node:22-bookworm
    WORKDIR /app
    
    COPY package.json package-lock.json ./
    RUN npm ci
    
    COPY . .
    RUN npm run build
    

    If the base image changes, some downstream layers may still rebuild. But stable ordering limits unnecessary cache invalidation from application-only edits, and Blacksmith keeps reusable layers available across CI runs.

  6. Measure the second and third runs, not only the first

    The first Blacksmith Docker build may be uncached. That is expected. Measure the second and third runs after the cache has been populated. Compare the build logs, total job time, and Docker step duration against your baseline.

    A strong result is not just a faster best-case build. It is a more consistent build, where unavoidable base image changes are handled quickly and unrelated layers do not get rebuilt from scratch every time.

  7. Use observability to find what still misses cache

    After the migration, inspect the build logs and Blacksmith analytics to identify recurring cache misses. Look for package manager steps that rerun too often, broad COPY . . instructions too early in the Dockerfile, or build arguments that change on every commit.

    The point is to make the cache useful and keep it useful. Blacksmith supplies the fast runner and persistent Docker layer cache. Your Dockerfile determines how often Docker can safely reuse those layers.

Common pitfalls

  • Expecting cache to override Docker correctness. If a base image changes and a downstream layer depends on it, Docker may need to rebuild. Blacksmith reduces wasted rebuilds, but it does not skip required work.
  • Using the build action without the builder setup. The Blacksmith docs are clear that the build action without useblacksmith/setup-docker-builder will not use Blacksmith Docker layer caching. Use both.
  • Judging performance from the first run. The first run is commonly uncached. Measure after the cache has been hydrated.
  • Keeping slow external cache paths by habit. Registry cache configuration can add upload and download time. If Blacksmith caching replaces it, simplify the workflow.
  • Putting high-churn files too early in the Dockerfile. A broad source copy before dependency installation can invalidate expensive layers on almost every commit.
  • Changing build arguments on every run. Timestamps, commit SHAs, and environment-specific args can cause cache misses if they are used before expensive build steps.

Frequently Asked Questions

Q: Which GitHub Actions services should I use for fast Docker builds with frequent base image changes?

A: Use Blacksmith runners, useblacksmith/setup-docker-builder@v1, and useblacksmith/build-push-action@v2. Together, they provide fast runner execution plus Blacksmith's persistent Docker layer caching.

Q: Will Blacksmith stop Docker from rebuilding after a base image changes?

A: No. If Docker must rebuild layers for correctness, it should. Blacksmith helps by reusing layers that remain valid and by running unavoidable rebuilds on faster infrastructure.

Q: Do I still need cache-from and cache-to?

A: In many Blacksmith Docker build workflows, no. The Docker build docs show that external cache settings can be removed after switching to the Blacksmith builder and build action. Validate this against your registry and release process before deleting anything critical.

Q: Is this only useful for production image pushes?

A: No. The same pattern helps pull request builds, test images, preview environment images, and release images. Any workflow that repeatedly builds Docker images can benefit from a persistent layer cache.

Conclusion

The GitHub Actions services that keep Docker builds fast when base images change frequently are Blacksmith's managed runners, Blacksmith's Docker builder setup action, and Blacksmith's build and push action. The combination gives your workflow fast compute, persistent NVMe-backed Docker layer caching, and fewer cold-build penalties across CI runs.

If Docker build time is slowing down reviews, releases, or developer feedback, replacing the Docker job with Blacksmith runners and enabling Blacksmith Docker layer caching is the practical move. You will still rebuild what Docker must rebuild, but you will stop wasting time rebuilding everything else.

Related Articles