What they're testing
Whether you understand Docker's layer model, or copied a Dockerfile from somewhere.
The short answer~30 seconds
Docker caches per layer: if an instruction and everything before it are unchanged, the layer is reused. So if you COPY . . before npm ci, any code change — even a README edit — invalidates the npm ci layer and reinstalls every dependency. Reverse it: copy package*.json, run npm ci, then copy the source — and dependencies only reinstall when package.json actually changes.
The long answer
Multi-stage builds are the next step and usually the biggest size win: the first stage has all the build tooling, the final stage copies only the artefacts into a minimal runtime image. A typical Node image goes from around 1.2GB to under 200MB — faster to pull when scaling out, and a smaller attack surface because no compiler ships to production.
A detail people miss: deleting a file in a later layer does NOT shrink the image. If you COPY a secret and RUN rm it in the next instruction, the file remains in the earlier layer and anyone can extract it from the image. It's one of the commonest ways credentials leak — sensitive material needs build secrets or a multi-stage boundary, not rm.
# Cache hỏng mỗi lần sửa bất kỳ file nào
COPY . .
RUN npm ci
# Cache chỉ hỏng khi dependency đổi
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run buildWhat they'll ask next
?COPY versus ADD?
ADD does two extra things: fetches URLs and auto-extracts tarballs. Both are implicit and surprising, so the official guidance is COPY unless you specifically want the extraction.
These lose points
- Running the container as root without mentioning it.
USER nodeis one line and it bounds the damage of anything inside. - Using the
latesttag for a base image. Builds stop being reproducible, and one day it breaks with nobody having changed anything.