Production Docker Multi-Stage Builds: Slashing Image Size by 85% & Hardening Container Security
From a bloated 1.2GB node_modules image to an 85MB ultra-lean Alpine container running as a non-privileged user.

DevOps & Cloud Architect
Principal Cloud Systems Engineer, Natelad Agency
Executive & Architectural Key Takeaways
- ✓Standard single-stage Docker builds leave compilers, devDependencies, and test runners inside production images, expanding the attack surface.
- ✓Next.js output: "standalone" automatically traces import dependencies and packages only required node_modules, shrinking images from >1GB to ~85MB.
- ✓Running containers as the default root user is an extreme security risk; always specify a dedicated unprivileged UID (e.g., nodejs:1001).
- ✓Pin base image digests (e.g. node:22-alpine@sha256:...) to guarantee deterministic builds and prevent upstream malicious tampering.
- 01.The Anatomy of a Bloated Production Container
- 02.Production Next.js Multi-Stage Dockerfile
- 03.Security & Runtime Optimization Checklist
The Anatomy of a Bloated Production Container
In many software teams, Dockerfiles start simple: COPY . ., npm install, and npm start. While this works in local development, the resulting image is often over 1.2 gigabytes in size. It contains TypeScript compilers, devDependencies, Git history, and package cache files.
Large containers slow down CI/CD deployments, consume massive bandwidth on container registries, and critically, dramatically widen the vulnerability surface for CVE exploits.
Production Next.js Multi-Stage Dockerfile
By splitting the build into three distinct stages (deps, builder, and runner), the final production image contains only the compiled JavaScript runtime and required public assets.
# Stage 1: Dependency resolution
FROM node:22-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
# Stage 2: Code Compilation & Asset Bundling
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
RUN npm run build
# Stage 3: Ultra-lean Production Runner
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Non-root user for security
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
CMD ["node", "server.js"]Security & Runtime Optimization Checklist
Always mount configuration secrets via Docker secrets or runtime environment injection rather than baking .env files into image layers.
Implement Docker layer caching with BuildKit by placing infrequently changed commands (like package.json copying) at the top of the Dockerfile.

DevOps & Cloud Architect
Principal Cloud Systems Engineer at Natelad Agency. Architecting mission-critical digital systems, resilient infrastructure, and security frameworks for enterprises worldwide.
Related Production Blueprints
View All Blueprints →Engineering Resilient Multi-WAN Networks: Combining Starlink Satellites with Dedicated Fibre
How we design mission-critical telecommunication grids for remote mining, banking, and industrial facilities by pairing high-throughput terrestrial fibre with low-earth-orbit (LEO) satellite redundancy.
Starlink Bypass Mode & MikroTik Integration: The Definitive Commercial Setup Guide
Step-by-step technical guide to putting Starlink Gen 2 and Gen 3 dishes into bypass mode, eliminating double-NAT issues, and configuring enterprise MikroTik routers for commercial offices.
Implement this architecture with Natelad’s dedicated engineering pods.
Book a technical discovery session with our lead architects to evaluate your infrastructure, review security posture, or scope a new platform sprint.