The base image has Node.js, but nothing of the shop. COPY copies files from the shop's folder on your computer, where you run docker build, into the image: COPY source destination. A . as the destination is the image's current folder, /app thanks to WORKDIR; with more than one file to copy, you write it as a folder, with a slash at the end: ./. RUN runs a command inside the image while it is being built, and keeps what the command changed.
Each line of a Dockerfile makes a layer, a saved change to the image, and Docker keeps the layers in a cache. On the next build it reuses a layer, CACHED, as long as the line and the files it copies have not changed. From the first line that changed, every line runs again. So the order matters: what changes rarely goes at the top, what changes often at the bottom.
Here is the same idea for a program built on Python: its package list, requirements.txt, is copied and installed first, and the code last.
const dockerfile = [
"FROM python:3.13-slim",
"WORKDIR /srv",
"COPY requirements.txt .",
"RUN pip install -r requirements.txt",
"COPY . .",
].join("\n");
Two files say which packages the shop needs: package.json, and package-lock.json, where npm wrote down the exact version of every package it installed on your computer. npm ci (a clean install) reads both and installs exactly the versions written in the lock file, into the folder node_modules.
The check builds your image, then changes app.js and builds again. When your lines are right, it prints:
$ docker build -t shop . [1/6] FROM node:22-slim [2/6] WORKDIR /app [3/6] ENV NODE_ENV=production [4/6] COPY package.json package-lock.json ./: copies package.json, package-lock.json into /app [5/6] RUN npm ci: installs express 5.1.0 and the packages it needs, in the exact versions written in package-lock.json [6/6] COPY . .: copies app.js, package.json, package-lock.json, Dockerfile into /app In the image: /app/package.json, /app/package-lock.json, /app/app.js, /app/Dockerfile You change app.js and build again: [1/6] FROM node:22-slim: CACHED [2/6] WORKDIR /app: CACHED [3/6] ENV NODE_ENV=production: CACHED [4/6] COPY package.json package-lock.json ./: CACHED [5/6] RUN npm ci: CACHED [6/6] COPY . .: runs again, app.js changed npm ci was CACHED: a change to the code does not install the packages again
Your task: after the three lines of the base, add three lines to the string dockerfile: copy package.json and package-lock.json into the current folder, ./; install the packages with npm ci; then copy the whole shop folder into the current folder. A change to app.js must leave the install CACHED.
Assignment
Follow the Coding Tutorial to add the COPY, RUN and COPY lines to the shop's Dockerfile, in that order.
Hint
In COPY source destination, a dot as the source means everything in the shop's folder, and a dot as the destination means /app. npm can only read package.json and package-lock.json once a line above it has copied them in.
Free plan: 30 tutor messages. PRO is unlimited.
