BuildKit features

Docker · Advanced · 14 min

These features cut CI build times dramatically and are the right way to use secrets during builds.

BuildKit is Docker's build engine (the default since Engine 23; docker build is an alias for docker buildx build). Beyond parallel stages and skipping unused ones, it adds Dockerfile features. Start the file with # syntax=docker/dockerfile:1 to get the latest stable syntax.

Cache mounts persist a directory across builds without putting it in the image:

RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt

Even when the layer's cache is invalidated, pip, npm, Go or apt find their download caches warm, so reinstalls take seconds.

Secret mounts expose a secret file to a single RUN without writing it into any layer or the build history:

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci

and build with docker build --secret id=npmrc,src=$HOME/.npmrc ..

SSH mounts (RUN --mount=type=ssh git clone git@github.com:acme/private.git with docker build --ssh default .) forward your SSH agent for private dependencies, with no keys copied.

Bind mounts (--mount=type=bind,source=.,target=/src) read files from the context without a COPY layer, useful when only build output is needed.

Heredocs let you write multi-line scripts inline: RUN <<EOF ... EOF.

Remote cache: CI runners start with empty caches. --cache-to type=registry,ref=ghcr.io/acme/api:buildcache,mode=max exports every layer's cache, and --cache-from with the same ref imports it on the next run (type=gha exists for GitHub Actions). Cache export to registries needs a builder using the docker-container driver or the containerd image store.

docker buildx du and docker buildx prune manage the builder's cache.

Example

# syntax=docker/dockerfile:1
FROM python:3.13-slim
WORKDIR /app
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    rm -f /etc/apt/apt.conf.d/docker-clean && \
    apt-get update && apt-get install -y --no-install-recommends git
RUN --mount=type=cache,target=/root/.cache/pip \
    --mount=type=bind,source=requirements.txt,target=requirements.txt \
    --mount=type=secret,id=pipconf,target=/etc/pip.conf \
    pip install -r requirements.txt
COPY . .
CMD ["python", "main.py"]

# docker build --secret id=pipconf,src=$HOME/.config/pip/pip.conf \
#   --cache-from type=registry,ref=ghcr.io/acme/app:cache \
#   --cache-to type=registry,ref=ghcr.io/acme/app:cache,mode=max -t app .

Remember

  • RUN --mount=type=cache keeps package caches warm across builds
  • Secret and SSH mounts give a single step access without leaking into layers
  • Export/import cache to a registry so CI builds aren't cold
  • Begin Dockerfiles with # syntax=docker/dockerfile:1

Watch out for

  • Expecting a cache mount's contents to be in the final image — they're only available during that RUN.

Check yourself

  1. How does a BuildKit secret mount differ from COPY-ing a token file?
  2. Your CI builds always start cold. Which feature helps most?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.docker.com/build/buildkit/