Docker BuildKit — The Modern Build Engine
What Is Docker BuildKit in Simple Terms?
BuildKit is the new build engine that replaced Docker's original build system. It builds faster (parallel execution), produces smaller images (better cache management), handles secrets safely (secret mounts that never appear in layers), and supports building for multiple CPU architectures from a single machine.
If you are on Docker 23+ it is already on by default. On older versions you enable it with one environment variable.
Legacy builder: BuildKit:Layer 1 builds Layer 1 buildsLayer 2 builds Layer 2 builds <- parallelLayer 3 builds Layer 3 builds <- parallelLayer 4 builds Layer 4 buildsTotal: 4 minutes Total: 2.5 minutesEnabling BuildKit
# Enable for a single buildDOCKER_BUILDKIT=1 docker build . # Enable permanently (add to ~/.bashrc or ~/.zshrc)export DOCKER_BUILDKIT=1 # Enable in daemon config (for all users on this host)# /etc/docker/daemon.json{ "features": { "buildkit": true } } # Docker 23+ — already enabled by defaultdocker build . # uses BuildKit automatically # Use docker buildx (always uses BuildKit)docker buildx build .BuildKit Features
Secret mounts — build-time secrets that never appear in layers:
# syntax=docker/dockerfile:1 RUN --mount=type=secret,id=github_token \ GITHUB_TOKEN=$(cat /run/secrets/github_token) \ npm install --registry https://npm.pkg.github.com# Token never stored in any layerdocker buildx build \ --secret id=github_token,src=$HOME/.secrets/github-token \ -t myapp:latest .Cache mounts — package manager caches between builds:
RUN --mount=type=cache,target=/root/.npm \ npm ci --omit=dev# npm cache reused between builds, NOT in the imageSSH mounts — access private repos during build:
RUN --mount=type=ssh \ git clone git@github.com:myorg/private-repo.gitdocker buildx build --ssh default=$SSH_AUTH_SOCK .Multi-platform builds:
# Build for both AMD64 and ARM64docker buildx build \ --platform linux/amd64,linux/arm64 \ --push \ -t registry.razorpay.in/payment-api:v3.1.0 .# One command produces images for both architectures# Docker pushes a manifest list — clients pull the right arch automaticallyBuildKit Syntax Header
# syntax=docker/dockerfile:1# This line at the top unlocks all BuildKit features# Without it, secret mounts and cache mounts are not available FROM node:20-alpine# ... rest of DockerfileInline Build Cache
# Export cache to registry (share cache between CI runs)docker buildx build \ --cache-from type=registry,ref=registry.razorpay.in/payment-api:cache \ --cache-to type=registry,ref=registry.razorpay.in/payment-api:cache,mode=max \ --push \ -t registry.razorpay.in/payment-api:v3.1.0 . # GitHub Actions cache (simpler)docker buildx build \ --cache-from type=gha \ --cache-to type=gha,mode=max \ .PLACEMENT PRO TIP**Tip:** Always add `# syntax=docker/dockerfile:1` as the first line of Dockerfiles that use any BuildKit features (secret mounts, cache mounts, SSH mounts). Without this header, Docker may use the legacy parser and ignore BuildKit-specific syntax.
REMEMBER THIS**Remember:** Secret mounts (`--mount=type=secret`) are the correct way to use API keys, GitHub tokens, and SSH keys during builds. They are completely invisible in the final image and in `docker history`. There is no excuse for putting build-time credentials in ENV or ARG instructions when BuildKit secret mounts are available.