What are the key Dockerfile instructions?

6 minbeginnerdockerfilefundamentals

Quick Answer

FROM sets the base image. RUN executes a command at build time, creating a new layer. COPY/ADD bring files from the build context into the image. WORKDIR sets the working directory for later instructions. ENV sets persistent environment variables. EXPOSE documents which ports the container listens on — informational only, it doesn't actually publish them. USER sets which user later instructions and the container's process run as. CMD/ENTRYPOINT define what runs when a container starts.

Detailed Answer

A representative Dockerfile

FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]

Instruction by instruction

  • FROM — every Dockerfile starts with a base image. This sets the starting filesystem layers and OS/runtime foundation everything else builds on.
  • RUN — executes a command at build time and commits its filesystem changes as a new layer. Used for installing packages, compiling code, or other build-time setup.
  • COPY — copies files/directories from the build context (the directory you run docker build from) into the image's filesystem.
  • WORKDIR — sets the working directory for all following RUN, CMD, COPY, etc. Similar to running cd, but it persists across instructions and creates the directory if it doesn't exist.
  • ENV — sets an environment variable that persists into the running container, visible to the application at runtime. This is different from ARG, which only exists during the build.
  • EXPOSE — purely documentation. It tells anyone reading the Dockerfile, and tools like docker network, which ports the app listens on. It doesn't actually publish or open that port — you still need -p on docker run for that.
  • USER — sets which user later instructions run as, and which user the container's main process runs as by default. Important for not running as root.
  • CMD and ENTRYPOINT — both define what runs when a container starts, with an important behavioral difference between the two.

Additional instructions worth knowing

ARG BUILD_VERSION=dev          # build-time-only variable (see the ARG vs ENV question)
LABEL maintainer="team@example.com"   # arbitrary metadata attached to the image
VOLUME /data                    # documents/declares a mount point (see the storage topic)
HEALTHCHECK CMD curl -f http://localhost/health || exit 1   # see the container lifecycle topic

Why instruction order matters beyond just readability

Each instruction that touches the filesystem — RUN, COPY, ADD — creates a new cached layer. Docker's build cache invalidates from the first changed instruction onward, and every instruction after that must re-run, even if its own inputs didn't change. A Dockerfile is really executable documentation of how to build and run the application. That's why it deserves the same deliberate structure as any other piece of code, not just whatever order felt natural while developing.

Related Resources