A real walkthrough of shrinking bloated Docker images from 1.2GB to 240MB using multi-stage builds, Alpine, and dependency auditing.
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.
A quick docker history revealed the culprits:
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.
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.
Running npx depcheck found 12 unused packages. We removed them and dropped another 70MB.
| Metric | Before | After |
|---|---|---|
| Image size | 1.2GB | 240MB |
| Pull time | 38s | 8s |
| Cold start | 45s | 12s |
| Registry cost | $180/mo | $40/mo |
npm ci --omit=dev to exclude dev dependenciesdocker scout or trivySmall images mean faster deploys, cheaper storage, and a smaller attack surface. There's no reason to ship your test framework to production.
Get the latest tutorials, guides, and insights on AI, DevOps, Cloud, and Infrastructure delivered directly to your inbox.
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.
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.
Explore more articles in this category
Helm gives you a lot of rope. The patterns we used that backfired, the ones we replaced them with, and what to skip if you're starting today.
We run three different job queue systems across our services. The patterns that work across all of them, the differences that matter, and the operational gotchas.
We adopted Backstage for service catalogs and templates. What works, what was over-engineered for our size, and what we'd do differently.