How to Shrink Docker Images

A
Author
08 Aug, 2026 1 min read 417 views

Smaller images pull faster, start faster, cost less to store and contain fewer packages with vulnerabilities. Going from 1.2 GB to under 200 MB is common.

1. Choose a smaller base image

  • node:22 (Debian full) - large, has build tools.
  • node:22-slim - Debian with the extras removed; good compatibility.
  • node:22-alpine - very small; uses musl libc, which occasionally breaks native modules.
  • Distroless images - just the runtime, no shell or package manager. Smallest attack surface.
  • scratch - empty; perfect for static Go or Rust binaries.

2. Use multi-stage builds

FROM golang:1.25 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app ./cmd/api

FROM gcr.io/distroless/static-debian12
COPY --from=build /app /app
USER nonroot
ENTRYPOINT ["/app"]

The Go toolchain (hundreds of MB) never reaches the final image, which ends up a few MB in size.

3. Clean up in the same layer

# Bad: the cache is deleted in a new layer but still stored in the previous one
RUN apt-get update && apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# Good
RUN apt-get update \
 && apt-get install -y --no-install-recommends curl \
 && rm -rf /var/lib/apt/lists/*

4. Ship only production dependencies

RUN npm ci --omit=dev
# Python: pip install --no-cache-dir -r requirements.txt  (or uv sync --no-dev)

5. See where the space goes

docker images my-api
docker history my-api:latest     # size of each layer
dive my-api:latest                # interactive layer explorer (third-party tool)

6. Keep the build context lean

A good .dockerignore keeps node_modules, .git, test fixtures and build output out of COPY . ..

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.