← Back to all articles
DockerDecember 8, 2025📖 6 min read

Docker Image Optimization: 1.2GB → 45MB

Multi-stage builds, distroless images, and layer-caching tricks that make your images tiny and your deploys fast.

Neeraj Kumar

Neeraj Kumar

Cloud & DevOps Engineer

A student once showed me a Node.js API image that weighed 1.2 GB. Twenty minutes later it was 45 MB, deployed 8× faster, and had a fraction of the CVEs. Here is exactly what we did, step by step.

Step 1: Stop shipping the build environment (1.2GB → 350MB)

The original image was FROM node:20 with the entire source tree, dev dependencies and npm cache inside. Multi-stage builds separate building from running:

dockerfile
# build stage
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

# runtime stage
FROM node:20-slim
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

Step 2: Smaller base image (350MB → 130MB)

node:20-slim strips build tools and docs. Alpine (node:20-alpine) goes further but uses musl instead of glibc — test native modules carefully. For most APIs, slim is the sweet spot of small + compatible.

Step 3: Distroless (130MB → 45MB)

Google's distroless images contain your runtime and nothing else — no shell, no package manager, no OS utilities. Smaller image, and dramatically smaller attack surface: Trivy findings dropped from 40+ to single digits.

dockerfile
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
CMD ["dist/server.js"]

Step 4: Layer-cache like you mean it

  • COPY package*.json and npm ci before COPY . . — dependency layers rebuild only when the lockfile changes.
  • Use a .dockerignore: node_modules, .git, dist, coverage. The build context shrinks from hundreds of MB to a few.
  • In CI, enable BuildKit cache mounts or registry cache so builds reuse layers across runners.

Why this matters beyond disk space

Small images pull faster, so pods start faster, so autoscaling reacts faster and deployments finish sooner. They also carry fewer packages, which means fewer CVEs to patch and a quieter security dashboard. Image size is not vanity — it is an operational metric.

CloudCodeAI — Empower Engineering

Enjoyed this article?

I share AWS & DevOps tutorials on my YouTube channel CloudCodeAI and train engineers hands-on.