Best Practices
Practical habits for smaller, faster, and more secure Docker images
Overview
Following a few best practices keeps your images small, your builds fast, and your containers secure. Small images pull faster and have a smaller attack surface, while good layer ordering makes rebuilds nearly instant. These habits pay off as soon as you share images with a team or deploy them.
Syntax / Usage
Two of the highest-impact techniques are multi-stage builds (to drop build tooling from the final image) and a .dockerignore file (to keep junk out of the build context).
# Stage 1: build
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: slim runtime image
FROM node:20-alpine
WORKDIR /app
COPY /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
Examples
A .dockerignore keeps large or sensitive files out of the build context:
node_modules
.git
.env
*.log
Pin base image versions instead of relying on latest for reproducible builds:
FROM python:3.12.4-slim
Common Mistakes
- Using
latesttags, which makes builds non-reproducible - Copying source before installing dependencies, breaking the layer cache
- Running containers as root instead of a dedicated non-root
USER - Baking secrets into image layers where they remain recoverable
- Shipping build tools and dev dependencies in the final production image
See Also
docker-dockerfile docker-images-and-containers docker-compose