How We Cut Our Docker Image Size by 80% and Why It Matters
A real walkthrough of shrinking bloated Docker images from 1.2GB to 240MB using multi-stage builds, Alpine, and dependency auditing.
Key takeaways
A real walkthrough of shrinking bloated Docker images from 1.2GB to 240MB using multi-stage builds, Alpine, and dependency auditing.
On this page
How We Cut Our Docker Image Size by 80% and Why It Matters#
Our main API image had grown to 1.2GB. Deploys were slow, registry costs were climbing, and cold starts on Kubernetes took 45 seconds. Here's exactly how we fixed it.
The Problem#
A quick docker history revealed the culprits:
- Full Node.js 18 base image (900MB layer)
- Dev dependencies included in the final image
- Leftover build artifacts and cache directories
Step 1: Multi-Stage Builds#
We split the Dockerfile into build and runtime stages:
# Build stage
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime stage
FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/index.js"]
This alone dropped us from 1.2GB to 480MB.
Step 2: Prune Dev Dependencies#
We added a production-only install in the runtime stage:
FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
Down to 310MB.
Step 3: Audit What's Left#
Running npx depcheck found 12 unused packages. We removed them and dropped another 70MB.
Results#
| Metric | Before | After |
|---|---|---|
| Image size | 1.2GB | 240MB |
| Pull time | 38s | 8s |
| Cold start | 45s | 12s |
| Registry cost | $180/mo | $40/mo |
Best Practices#
- Always use multi-stage builds for compiled or bundled applications
- Use Alpine or distroless base images in production
- Run
npm ci --omit=devto exclude dev dependencies - Add a .dockerignore to prevent copying node_modules, .git, and test files
- Audit images quarterly with
docker scoutortrivy
Small images mean faster deploys, cheaper storage, and a smaller attack surface. There's no reason to ship your test framework to production.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
Model Fallback Policies for Customer-Facing AI: The Routing Rules That Kept SLA Intact
A real-world model fallback guide for customer-facing AI systems, covering how one team preserved response quality and support SLAs during a partial provider degradation.
AWS Cost Audit: 7 Things We Found Wasting Money Every Month
A real cost audit uncovered idle load balancers, oversized RDS instances, and forgotten snapshots. Here's what we found and how we fixed each one.
More from DevOps
Explore more articles in this category
Best Managed Kubernetes in 2026: EKS vs GKE vs AKS vs DOKS
The control plane fee is the least interesting number. What separates managed Kubernetes providers is upgrade cadence, how much they run for you, and where the node bill lands.
Best Log Management Tools in 2026: What You Actually Pay For
Every log platform looks affordable at proof-of-concept volume and expensive at production volume. The pricing model, not the feature list, decides which one you can live with.
Your CI Runner Is the Target: Hardening Against npm Worms
The keyv compromise reached 444 packages and over two billion monthly installs through preinstall scripts. The controls that actually stop it are boring and mostly free.
You might have missed
Evergreen posts worth revisiting.