One Dockerfile Line That Cuts Build Times in Half

Share

If your CI pipeline reinstalls node_modules from scratch every single time, you're watching money burn. BuildKit's --mount=type=cache directive fixes this with one line — and somehow most Dockerfiles still don't use it.

What It Does

The cache mount tells BuildKit to stash a directory (like your npm or pip cache) between builds. It's not part of your image layer, so it doesn't bloat your final image. It just sits in the build cache, ready for next time.

This works for any package manager with a cache directory: npm, pip, apt, cargo, maven, gradle — all of them.

Before vs After

Before — reinstalling the world every build:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

After — cache that actually sticks:

# syntax=docker/dockerfile:1
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .
RUN npm run build

That # syntax=docker/dockerfile:1 line at the top is required — it enables BuildKit frontend features. Without it, the mount flag gets silently ignored. Yes, silently. Fun debugging.

Other Package Managers

Python:

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

apt (add sharing=locked for concurrent builds):

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && apt-get install -y curl

One Gotcha

Cache mounts are scoped per-builder instance. If your CI spins up a fresh runner every time (looking at you, GitHub Actions free tier), the cache resets. Pair this with docker buildx and a persistent cache backend — like --cache-to=type=gha — to share it across runs. That's where the real compound speedup lives.

TL;DR

  • Add # syntax=docker/dockerfile:1 to the top of your Dockerfile — without it, cache mounts silently do nothing
  • Use --mount=type=cache,target=<cache-dir> before any RUN that installs dependencies
  • Combine with a persistent cache backend (type=gha, type=registry) in CI for compounding speedups across runs