CoursesDocker for beginnersBuilding your own images

Writing a Dockerfile

Turn an app into an image.

Beginner12 min · lesson 9 of 16
In plain terms
A Dockerfile is a recipe card the kitchen follows step by step — start with this base, add these ingredients, then this is how you serve it. Follow the card and you get the same dish (image) every time.

So far you have run images other people built; now you build your own. A Dockerfile is a plain-text recipe: a list of instructions Docker follows top to bottom to assemble an image. It starts FROM a base image, copies your app in, runs any build steps, and declares what to execute when a container starts. The whole thing is deliberately small and readable — most real Dockerfiles are under twenty lines.

Dockerfile
FROM node:22-alpine # start from a small Node base image
WORKDIR /app # set the working directory inside the image
COPY package*.json ./ # copy dependency manifests first (see the layers lesson)
RUN npm ci --omit=dev # install dependencies at build time
COPY . . # copy the rest of the source
EXPOSE 3000 # document the port the app listens on
CMD ["node", "server.js"] # the command that runs when the container starts

Build it, then run it

docker build turns the Dockerfile into an image. The -t flag tags it with a name, and the final argument (usually a dot) is the build context — the directory Docker sends to the daemon and can COPY from. Once built, you run it exactly like any other image.

terminal
$ docker build -t payments-api:1.0 .
[+] Building 12.4s ... => naming to payments-api:1.0
$ docker run -d -p 3000:3000 payments-api:1.0
$ curl -s localhost:3000/healthz
ok

The instructions you will actually use

A handful cover most needs. FROM chooses the base. WORKDIR sets the directory for the instructions that follow. COPY brings files from the build context into the image (prefer it over ADD, which does extra magic you rarely want). RUN executes a command at build time and bakes the result into a layer. ENV sets defaults. EXPOSE documents a port. CMD and ENTRYPOINT — the next lesson — say what runs at start.

Write a .dockerignore
The build context is everything in the directory you point at, and it is sent to the daemon and available to COPY. Without a .dockerignore you can accidentally ship .git, node_modules, or a stray .env full of secrets into your image. Add the ignore file before your first build, listing .git, node_modules, and anything sensitive.