DO

Dockerfile Best Practices

Image building conventions, layer optimization, and Dockerfile structure

Details

Language / Topic
dockerDocker
Category
Style Guide

Rules

balanced
- Use multi-stage builds to separate build dependencies from runtime — keep production images minimal
- Pin base image versions with SHA digests or specific tags, never use :latest in production Dockerfiles
- Order instructions from least to most frequently changing to maximize layer cache hits
- Use .dockerignore to exclude node_modules, .git, test files, and build artifacts from the build context
- Run as non-root user: add USER directive after installing dependencies
- Use multi-stage builds: build stage with full toolchain, final stage with minimal runtime (distroless, alpine, slim)
- Pin base images: FROM node:22.14-slim@sha256:abc123 or at minimum FROM node:22.14-slim — never :latest
- Order Dockerfile instructions for cache efficiency: COPY package*.json → RUN npm ci → COPY . (source last)
- Use .dockerignore: exclude node_modules, .git, .env, test/, docs/, *.md, and IDE config files
- Run as non-root: RUN adduser --system appuser && USER appuser — never run production containers as root
- Combine RUN commands with && to reduce layers; use heredocs (RUN <<EOF) for multi-line scripts
- Set explicit WORKDIR instead of using cd commands; use absolute paths throughout
- Use COPY --from=build to selectively copy only built artifacts from build stages
- Add health check: HEALTHCHECK CMD curl -f http://localhost:3000/health || exit 1
- Use ARG for build-time variables, ENV for runtime; don't use ENV for build-only values (they persist)
- Pin dependency versions in RUN commands: apt-get install -y curl=7.88.1-10 — reproducible builds
- Add labels for metadata: LABEL org.opencontainers.image.source, version, description