gotchadockerMajor
Dockerfile layer cache breaks when frequently-changing files are copied early
Viewed 0 times
layer cachenpm installpip installbuild speedcache invalidationcopy order
Problem
Every
RUN npm install or RUN pip install re-runs on every build even when dependencies haven't changed, making builds slow. This happens when source code is copied before dependency installation.Solution
Copy dependency manifests first, install dependencies, then copy the rest of the source. Docker caches each layer; copying the manifest separately means the install layer is only invalidated when the manifest changes.
# GOOD — install layer cached unless package.json changes
COPY package.json package-lock.json ./
RUN npm ci
COPY . .Why
Docker builds layers sequentially and caches each one based on its inputs. Once any layer is invalidated (because an input changed), all subsequent layers must be rebuilt. Putting volatile files early poisons the cache for expensive steps below them.
Gotchas
- COPY . . copies everything including source code — put this after dependency installation
- Use .dockerignore to exclude node_modules, .git, and build artifacts so they don't pollute the COPY layer hash
- For monorepos you may need to COPY the workspace root manifest plus the package manifest separately
- ARG values before a RUN also bust the cache — place ARGs after expensive cached layers
Code Snippets
Correct dependency-first layer ordering
# BAD — source copy busts npm install cache on every change
FROM node:20-alpine
WORKDIR /app
COPY . . # <-- any file change invalidates everything below
RUN npm ci
CMD ["node", "server.js"]
# GOOD — install layer only rebuilds when package files change
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]Context
Any Dockerfile that installs dependencies from a manifest file
Revisions (0)
No revisions yet.