Skip to content
Latchkey
Documentation menu

Docker layer caching

Latchkey Docker Cache Build wraps docker buildx with registry-backed layer caching, so repeat image builds reuse every unchanged layer across ephemeral runners.

Every Latchkey runner is a fresh, isolated instance. That is good for security and bad for Docker's local layer cache, which disappears with the runner. Latchkey Docker Cache Build solves it with a layer cache stored in a private container registry managed by Latchkey for your organization: matching layers from earlier builds are reused, and the updated cache is written back for the next run.

Add it to your workflow#

.github/workflows/build.yml
jobs:
  build:
    runs-on: latchkey-medium
    steps:
      - uses: actions/checkout@v4
      - uses: latchkey-dev/docker-cache-action@v1
        with:
          context: .
          tags: myapp:latest
          push: true

That is the whole integration: you supply the inputs you would give any Docker build, and Latchkey handles the registry, the credentials, and the cache wiring. By default the action uses cache-mode: max, which caches all layers including intermediate layers from multi-stage builds. Single-platform builds with push: false load the built image into the runner's local Docker daemon.

What layer caching is worth: a worked example#

Illustrative numbers, not a measured benchmark. Take a multi-stage Node.js image that builds in ~8 minutes uncached: base image, system packages, dependency install, compile, assemble. With the layer cache in place, a source-only change invalidates just the final layers; everything above them is pulled from the registry cache, and the rebuild lands in the 1 to 2 minute range. A commit that touches the dependency stage invalidates more layers and rebuilds more, so the win scales with how much of your Dockerfile a typical change leaves untouched. The default cache-mode: max trades a bigger cache push after the build for better hit rates on exactly these multi-stage rebuilds, since intermediate stage layers are cached too.

Illustrative build time (min)
No layer cache~8 min
Layer cache, source-only change~1-2 min

Inputs and outputs#

InputDefaultWhat it does
tagsrequiredTags for the built image
context.Build context path
dockerfileDockerfilePath to the Dockerfile
pushfalsePush the built image
build-argsnoneBuild arguments; values are masked in logs since they may contain secrets
targetnoneTarget stage for multi-stage builds
platformsnoneTarget platforms for the build
cache-modemaxCache scope: min or max (max caches all layers, including intermediate multi-stage layers)
cache-tagcacheRegistry tag used for the layer cache
extra-cache-from / extra-cache-tononeAdditional cache sources and destinations passed to the build
OutputWhat it tells you
cache-configuredtrue when registry layer caching was active for the build, false otherwise
image-digestDigest of the built image

Safe on any runner#

  • On non-Latchkey runners (for example GitHub-hosted), the action detects the cache registry is not available and builds normally, without cache flags. One workflow file stays portable across runner types.
  • On a repository's first build the cache is empty; if a cached build fails on that first run, the action automatically retries without cache. First runs never break because of caching.
  • Build-arg values are masked in logs, so secrets passed as build args do not leak into job output.
  • Caches are isolated per organization.

References