Docker Build Taking Too Long — Cache and Speed Fixes (2026)
Docker builds taking 10+ minutes every time? Here's how to fix layer caching, use BuildKit properly, and cut build times by 80% with multi-stage builds and cache mounts.
Slow Docker builds kill developer productivity and bloat CI costs. Here's every fix — from simple layer ordering to BuildKit cache mounts.
Why Docker Builds Are Slow
- Layer cache invalidation — wrong layer order busts the cache every time
- BuildKit disabled — old builder is slower and less intelligent
- Large build context — sending GBs to the Docker daemon
- No cache mounts — reinstalling all dependencies every build
- Single-stage builds — building everything in one fat image
Fix 1: Order Layers Correctly (Most Common Issue)
Docker caches each layer. When a layer changes, all subsequent layers rebuild. Put things that change least at the top.
Wrong order (cache busts on every code change):
FROM node:20-alpine
WORKDIR /app
COPY . . # copies everything — breaks cache on ANY file change
RUN npm install # reinstalls every time even if package.json didn't change
RUN npm run buildRight order (dependencies cached separately):
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./ # copy only package files first
RUN npm install # only reinstalls when package.json changes
COPY . . # now copy the rest
RUN npm run buildSame principle for Python:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt # cached until requirements.txt changes
COPY . .Fix 2: Enable BuildKit
BuildKit is faster, smarter, and supports cache mounts. It's the default in Docker Desktop but may not be in CI.
# Enable BuildKit
export DOCKER_BUILDKIT=1
docker build .
# Or in docker-compose
export COMPOSE_DOCKER_CLI_BUILD=1
export DOCKER_BUILDKIT=1
docker-compose buildIn GitHub Actions:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myapp:latest
cache-from: type=gha # GitHub Actions cache
cache-to: type=gha,mode=maxFix 3: Fix Your .dockerignore
If you're sending your entire repo to the Docker daemon, every build starts slow.
# Check your build context size
docker build . 2>&1 | head -5
# "Sending build context to Docker daemon 1.2GB" <-- this is your problemCreate .dockerignore:
.git
.github
node_modules
*.log
*.md
.env*
dist/
coverage/
.DS_Store
__pycache__
*.pyc
.pytest_cache
terraform/.terraform
*.tfstate
This alone can take your build context from 1GB to 10MB.
Fix 4: BuildKit Cache Mounts (Biggest Win)
Cache mounts let you persist package manager caches between builds. npm install with cache mount goes from 2 minutes to 10 seconds.
# syntax=docker/dockerfile:1
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
# --mount=type=cache persists the npm cache between builds
RUN --mount=type=cache,target=/root/.npm \
npm install
COPY . .
RUN npm run buildFor Python:
# syntax=docker/dockerfile:1
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
COPY . .For Go:
# syntax=docker/dockerfile:1
FROM golang:1.22-alpine
WORKDIR /app
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -o /app/server .Fix 5: Multi-Stage Builds
Single-stage builds install all dev tools and then ship them in the final image. Multi-stage builds separate build from runtime.
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Runtime (tiny image, no dev deps)
FROM node:20-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]Result: image goes from 1.2GB → 150MB. Pushes and pulls are faster too.
Fix 6: Remote Cache in CI
In CI, every build starts fresh. Use registry-based cache:
# GitHub Actions with registry cache
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myregistry.com/myapp:${{ github.sha }}
cache-from: type=registry,ref=myregistry.com/myapp:cache
cache-to: type=registry,ref=myregistry.com/myapp:cache,mode=maxWith ECR:
cache-from: type=registry,ref=123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:cache
cache-to: type=registry,ref=123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:cache,mode=maxMeasuring Improvement
# Time your build before and after
time docker build --no-cache . # baseline (cold)
time docker build . # with cache (warm)
# Check which layers are slow
docker build . 2>&1 | grep -E "CACHED|[0-9]+\.[0-9]+s"Typical results after these fixes:
- Cold build: 10 min → 4 min (multi-stage + better layers)
- Warm build: 4 min → 20 sec (cache mounts + BuildKit cache)
- CI build: 8 min → 45 sec (remote registry cache)
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
AWS ECR Push Denied: no basic auth credentials — Fix
Getting 'no basic auth credentials' or 'denied: Your authorization token has expired' when pushing to AWS ECR? Here are the exact commands to fix authentication for Docker, GitHub Actions, and Kubernetes.
Docker Build Fails in CI But Works Locally — Fix
Your Docker build works perfectly on your machine but fails in GitHub Actions, GitLab CI, or Jenkins. Here's every reason this happens and exactly how to fix it.
Docker Build Slow and Not Using Cache: 5 Fixes
Docker builds ignoring cache and rebuilding from scratch every time? These 5 fixes — Dockerfile layer ordering, BuildKit cache mounts, .dockerignore issues, and multi-stage optimizations — cut build times by 60-80%.