HomebaseWorks
Lesson 1 of 4

Writing a Dockerfile: instructions and layer caching

What FROM, WORKDIR, COPY, RUN, CMD and ENTRYPOINT do, and how ordering steps well makes builds fast.

EWritten by the HomebaseWorks editorial team · reviewed 26 Oct 2026

A Dockerfile is a recipe for building an image. Screenings test whether you know what each instruction does and whether you can order them so builds are quick and containers start correctly.

Advertisement

The main instructions

FROM node:20-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
  • FROM sets the base image. Pick a specific version tag rather than relying on latest.
  • WORKDIR sets the folder for the following instructions and is created if missing.
  • COPY copies files from the build context into the image. ADD can also extract local tar files and fetch URLs, so use COPY unless you need those.
  • RUN runs a command at build time, such as installing packages, and saves the result as a layer.
  • EXPOSE documents the port the app listens on. It does not publish the port on its own.
  • CMD sets the default command when a container starts.

CMD versus ENTRYPOINT

ENTRYPOINT fixes the program that always runs. CMD provides default arguments or a default command that users can replace by adding arguments to docker run.

ENTRYPOINT ["python", "app.py"]
CMD ["--port", "8000"]

Running docker run myapp starts python app.py --port 8000, while docker run myapp --port 9000 starts python app.py --port 9000. Use the JSON exec form shown here so the program runs as the main process and receives the stop signal from docker stop.

Layers and caching

Each instruction produces a layer. On a rebuild, Docker reuses cached layers until it reaches an instruction whose input has changed, then rebuilds that one and every one after it. That is why the example copies only the dependency files before npm ci: a change to your source code invalidates only the final COPY . . layer, and the slow install is reused.

Two more points help: combine related package commands into one RUN and clean package caches in the same step, and add a .dockerignore file listing folders such as .git and node_modules so they are not sent to the builder.

Common mistakes

  • Copying all source before installing dependencies, so every code change triggers a full reinstall.
  • Using RUN where CMD was meant, which runs the app during the build instead of at start.
  • Putting secrets such as API keys in the Dockerfile, where they stay in the image layers.

Habit: order your Dockerfile from what changes least to what changes most, and check with a second build that the dependency step shows as cached.

Advertisement
Continue with Docker4 lessons · 1 interview set · 1 test · 1 certificate
Not tested

More in Cloud and DevOps