A Dockerfile is a script composed of instructions to build a Docker image. Each instruction creates a layer in the image.
# Comment
INSTRUCTION arguments
FROM
Specifies the base image.
FROM ubuntu:20.04
FROM node:22-alpine
LABEL
Adds metadata to the image.
LABEL maintainer="you@example.com"
LABEL version="1.0" description="My App"
ENV
Sets environment variables.
ENV NODE_ENV=production
ENV PATH="/app/bin:$PATH"
RUN
Executes commands in a shell during build.
RUN apt-get update && apt-get install -y curl
RUN npm install
Use RUN ["executable", "param1", "param2"]
for JSON array form.
COPY
Copies files from host to image.
COPY . /app
COPY config.json /app/config.json
ADD
Similar to COPY
, but supports remote URLs and auto-extracts archives.
ADD https://example.com/file.tar.gz /app/
ADD archive.zip /app/
CMD
Sets default command to run when container starts.
CMD ["node", "server.js"] # Preferred exec form
CMD node server.js # Shell form
Only one CMD
allowed; later ones override earlier.
ENTRYPOINT
Configures a container to run as an executable.
ENTRYPOINT ["python", "app.py"]
Use with CMD
to pass default arguments.
WORKDIR
Sets the working directory for subsequent instructions.
WORKDIR /app
EXPOSE
Documents the port the container listens on.
EXPOSE 80
EXPOSE 443
Note: This does not publish the port.
VOLUME
Creates a mount point for persistent or shared data.
VOLUME ["/data"]
USER
Sets the user to run subsequent instructions.
USER appuser
ARG
Defines build-time variables.
ARG VERSION=1.0
RUN echo $VERSION
Use --build-arg VERSION=2.0
during docker build
.
ONBUILD
Triggers instructions when the image is used as a base.
ONBUILD COPY . /app
alpine
) for smaller size.RUN
commands to reduce layers..dockerignore
to exclude unnecessary files.COPY
over ADD
unless you need archive extraction.ENTRYPOINT
for fixed commands and CMD
for arguments.FROM node:22-alpine
LABEL maintainer="guillaume@example.com"
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
ENV NODE_ENV=production
CMD ["node", "index.js"]
# Build image
docker build -t my-app .
# Run container
docker run -p 3000:3000 my-app
node_modules
*.log
Dockerfile
.git
Multistage builds allow you to use multiple FROM
statements in one Dockerfile to optimize image size and separate build dependencies from runtime.
# Stage 1: Build
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Stage 2: Production
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
You can name each stage using AS <name>
and reference it later with --from=<name>
.
FROM golang:1.21 AS build
WORKDIR /src
COPY . .
RUN go build -o myapp
FROM alpine:latest
COPY --from=build /src/myapp /usr/local/bin/myapp
ENTRYPOINT ["myapp"]
Use COPY --from=<stage>
to copy files from one stage to another.
COPY --from=builder /app/output /app/output
You can copy:
Multistage builds help you avoid bloated images:
# Without multistage: includes compilers, source code, etc.
# With multistage: only includes runtime essentials
# Build stage
FROM node:22 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Serve stage
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]