Dockerfile Cheat Sheet
Quick reference for writing Dockerfiles: base images, instructions, multi-stage builds, best practices, and .dockerignore.
Containers & Cloud
docker
dockerfile
containers
A Dockerfile is a text file that describes how to assemble a container image. Each instruction creates a layer; the order of instructions determines the build steps and heavily influences cache efficiency.
Core Instructions
Table
| Instruction | Purpose | Example |
|---|---|---|
FROM image[:tag] | Base image for the build stage | FROM node:22-alpine |
WORKDIR /app | Set the working directory for RUN/COPY/CMD | WORKDIR /usr/src/app |
COPY src dst | Copy files from the build context into the image | COPY package.json ./ |
ADD src dst | Like COPY, plus URL and tar auto-extraction | ADD https://ex.com/x.tgz /opt/ |
RUN command | Execute a shell command during build | RUN npm ci --omit=dev |
ENV K=V | Set an environment variable for the container | ENV NODE_ENV=production |
ARG name | Build-time variable (not persisted) | ARG NODE_VERSION=22 |
EXPOSE port | Document the port the app listens on | EXPOSE 3000 |
CMD [...] | Default command; overridable at run time | CMD ["node", "server.js"] |
ENTRYPOINT [...] | Fixed command; args appended by CMD or CLI | ENTRYPOINT ["docker-entrypoint.sh"] |
USER user | Switch to a non-root user | USER node |
HEALTHCHECK ... | Health probe for orchestration | HEALTHCHECK CMD curl -f http://localhost/ |
A Minimal Node.js Dockerfile
dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build
FROM node:22-alpine AS runtime
ENV NODE_ENV=production
WORKDIR /app
COPY --from=build /app/.next ./.next
COPY --from=deps /app/node_modules ./node_modules
COPY package.json ./
EXPOSE 3000
USER node
CMD ["node_modules/.bin/next", "start"]
Multi-Stage Builds
Multi-stage builds let you use one image to compile and a smaller one to run. The AS name gives each stage a label; COPY --from=<stage> copies files between stages.
dockerfile
FROM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/app .
FROM gcr.io/distroless/static-debian12
COPY --from=build /bin/app /app
ENTRYPOINT ["/app"]
Benefits: the runtime image contains only the binary — no compiler, no source, no go toolchain.
Layer Caching & .dockerignore
Order matters for caching. Copy dependency manifests first, install, then copy source — a source change then reuses the cached dependency layer.
bash
# Copy dependency manifests first
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
# Source changes below reuse the install layer above
COPY . .
dockerignore
node_modules
.git
.next
dist
*.log
.env
Common Pitfalls
Table
| Pitfall | Fix |
|---|---|
| Running as root | Create a user and USER it before the final CMD. |
RUN npm install instead of npm ci | npm ci --frozen-lockfile is reproducible and faster in CI. |
COPY . . before installing deps | Breaks cache on every source change; copy manifests first. |
| Installing dev dependencies in runtime | Use multi-stage builds; keep dev deps only in the build stage. |
Large base image (node:latest) | Pin a slim/alpine or distroless base. |
Storing secrets in ENV | Use build secrets (RUN --mount=type=secret) instead. |