DEV Community

Darshan Vasani
Darshan Vasani Subscriber

Posted on

🐳 Docker Multi-Stage Build - Complete Documentation

🐳 Docker Multi-Stage Build - Complete Documentation

πŸ“‹ Table of Contents

🎯 What is Docker Multi-Stage Build?

Docker Multi-Stage Build is a powerful feature that allows you to use multiple FROM statements in a single Dockerfile[1]. Each FROM instruction creates a new stage in the build process, enabling you to optimize image size and improve security by separating build dependencies from runtime requirements[2].

πŸ”€ Key Concepts

  • πŸ—οΈ Multiple Stages: Each stage has its own base image and purpose
  • πŸ“¦ Selective Copying: Copy only necessary artifacts between stages
  • πŸ—‘οΈ Artifact Exclusion: Build tools and dependencies are left behind
  • 🎯 Production-Ready: Final image contains only runtime requirements

πŸš€ Why Use Multi-Stage Builds?

Multi-stage builds solve several critical problems in containerized application development[3]:

🎯 Benefit πŸ“‹ Description πŸ’‘ Impact
πŸ“‰ Smaller Image Size Excludes build tools and dependencies from final image πŸš€ Faster deployments
πŸ”’ Enhanced Security Reduces attack surface by removing unnecessary components πŸ›‘οΈ Lower vulnerability risk
⚑ Better Performance Lighter images load and start faster πŸƒ Improved runtime speed
🧹 Cleaner Workflow Single Dockerfile for entire build process πŸ› οΈ Simplified maintenance
πŸ’° Cost Optimization Reduced storage and bandwidth usage πŸ’΅ Lower infrastructure costs

πŸ—οΈ How Multi-Stage Builds Work

πŸ” Single-Stage vs Multi-Stage Comparison

graph TB
    subgraph "❌ Single-Stage Build Problems"
        SINGLE[πŸ“¦ Single Stage]
        SINGLE --> BUILD_TOOLS[πŸ”§ Build Tools]
        SINGLE --> SOURCE[πŸ“„ Source Code]
        SINGLE --> DEPS[πŸ“š All Dependencies]
        SINGLE --> ARTIFACTS[⚑ Build Artifacts]
        SINGLE --> FINAL1[πŸ“¦ Final Image: 200MB+]
    end

    subgraph "βœ… Multi-Stage Build Solution"
        STAGE1[πŸ—οΈ Build Stage]
        STAGE2[πŸš€ Runtime Stage]

        STAGE1 --> BUILD_TOOLS2[πŸ”§ Build Tools]
        STAGE1 --> SOURCE2[πŸ“„ Source Code]  
        STAGE1 --> BUILD_DEPS[πŸ“š Build Dependencies]
        STAGE1 --> COMPILE[βš™οΈ Compile/Build]

        STAGE2 --> RUNTIME_BASE[πŸƒ Runtime Base Image]
        STAGE2 --> COPY_ARTIFACTS[πŸ“‹ Copy Build Artifacts]
        STAGE2 --> FINAL2[πŸ“¦ Final Image: 50MB]

        COMPILE -.->|Copy Only Artifacts| COPY_ARTIFACTS
    end
Enter fullscreen mode Exit fullscreen mode

πŸ”„ Build Process Flow

sequenceDiagram
    participant User as πŸ‘€ Developer
    participant Docker as 🐳 Docker Engine
    participant Stage1 as πŸ—οΈ Build Stage (installer)
    participant Stage2 as πŸš€ Runtime Stage (deployer)
    participant Registry as πŸ“¦ Image Registry

    User->>Docker: docker build -t multistage .
    Docker->>Stage1: FROM node:18-alpine AS installer
    Stage1->>Stage1: WORKDIR /app
    Stage1->>Stage1: COPY package*.json ./
    Stage1->>Stage1: RUN npm install
    Stage1->>Stage1: COPY . .
    Stage1->>Stage1: RUN npm run build

    Docker->>Stage2: FROM nginx:latest AS deployer
    Stage2->>Stage1: COPY --from=installer /app/build /usr/share/nginx/html

    Docker->>User: πŸ“¦ Optimized Image Ready (50MB)
    User->>Registry: docker push multistage
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Step-by-Step Tutorial

πŸ› οΈ Project Setup

1. Clone the Application

git clone 
cd react-app-docker
ls  # Check project structure
Enter fullscreen mode Exit fullscreen mode

Project Structure:

react-app-docker/
β”œβ”€β”€ src/
β”œβ”€β”€ public/
β”œβ”€β”€ package.json
β”œβ”€β”€ package-lock.json
└── README.md
Enter fullscreen mode Exit fullscreen mode

πŸ“ Creating Multi-Stage Dockerfile

2. Create Dockerfile

touch Dockerfile
vi Dockerfile
Enter fullscreen mode Exit fullscreen mode

3. Multi-Stage Dockerfile Content

# πŸ—οΈ Stage 1: Build Stage (installer)
FROM node:18-alpine AS installer
WORKDIR /app

# Copy package files for dependency installation
COPY package*.json ./

# Install all dependencies (including devDependencies)
RUN npm install

# Copy source code
COPY . .

# Build the application
RUN npm run build

# πŸš€ Stage 2: Runtime Stage (deployer)
FROM nginx:latest AS deployer

# Copy only build artifacts from previous stage
COPY --from=installer /app/build /usr/share/nginx/html

# Nginx will serve the static files
EXPOSE 80
Enter fullscreen mode Exit fullscreen mode

πŸ”§ Build Process

4. Build the Multi-Stage Image

docker build -t multistage .
Enter fullscreen mode Exit fullscreen mode

πŸ“Š Build Output Analysis

graph LR
    subgraph "πŸ—οΈ Build Stage Process"
        A[πŸ“„ package.json] --> B[πŸ“¦ npm install]
        C[πŸ“ Source Code] --> B
        B --> D[βš™οΈ npm run build]
        D --> E[πŸ“ /app/build]
    end

    subgraph "πŸš€ Runtime Stage Process"
        F[🌐 nginx:latest] --> G[πŸ“‹ Copy build artifacts]
        E -.->|COPY --from=installer| G
        G --> H[🎯 Final Image]
    end

    style E fill:#90EE90
    style H fill:#87CEEB
Enter fullscreen mode Exit fullscreen mode

πŸ”„ Multi-Stage Build Workflow

🎯 Complete Workflow Diagram

flowchart TD
    START([πŸš€ Start Build Process]) --> STAGE1{πŸ—οΈ Build Stage}

    STAGE1 --> NODE[πŸ“¦ FROM node:18-alpine AS installer]
    NODE --> WORKDIR[πŸ“ WORKDIR /app]
    WORKDIR --> COPY_PKG[πŸ“‹ COPY package*.json ./]
    COPY_PKG --> NPM_INSTALL[⬇️ RUN npm install]
    NPM_INSTALL --> COPY_SRC[πŸ“„ COPY . .]
    COPY_SRC --> NPM_BUILD[βš™οΈ RUN npm run build]

    NPM_BUILD --> STAGE2{πŸš€ Runtime Stage}

    STAGE2 --> NGINX[🌐 FROM nginx:latest AS deployer]
    NGINX --> COPY_BUILD[πŸ“‹ COPY --from=installer /app/build /usr/share/nginx/html]
    COPY_BUILD --> FINAL[✨ Optimized Final Image]

    FINAL --> SIZE_CHECK{πŸ“ Size Check}
    SIZE_CHECK -->|Before: 200MB+| BEFORE[❌ Single Stage: Bloated]
    SIZE_CHECK -->|After: ~50MB| AFTER[βœ… Multi-Stage: Optimized]

    style STAGE1 fill:#FFE4B5
    style STAGE2 fill:#E0FFFF
    style FINAL fill:#90EE90
    style AFTER fill:#98FB98
Enter fullscreen mode Exit fullscreen mode

πŸ” Stage Dependency Graph

graph TB
    subgraph "πŸ“¦ Base Images"
        NODE18[🟒 node:18-alpine]
        NGINX[πŸ”΅ nginx:latest]
    end

    subgraph "πŸ—οΈ Build Stage (installer)"
        INSTALLER[installer stage]
        BUILD_DEPS[πŸ“š Build Dependencies]
        SOURCE_CODE[πŸ“„ Source Code]
        BUILD_ARTIFACTS[⚑ Build Artifacts]

        NODE18 --> INSTALLER
        INSTALLER --> BUILD_DEPS
        INSTALLER --> SOURCE_CODE
        BUILD_DEPS --> BUILD_ARTIFACTS
        SOURCE_CODE --> BUILD_ARTIFACTS
    end

    subgraph "πŸš€ Runtime Stage (deployer)"
        DEPLOYER[deployer stage]
        STATIC_FILES[πŸ“ Static Files Only]

        NGINX --> DEPLOYER
        BUILD_ARTIFACTS -.->|COPY --from=installer| DEPLOYER
        DEPLOYER --> STATIC_FILES
    end

    subgraph "πŸ—‘οΈ Excluded from Final Image"
        EXCLUDED[❌ node_modules❌ Source code❌ Build tools❌ Dev dependencies]
    end

    style BUILD_ARTIFACTS fill:#90EE90
    style STATIC_FILES fill:#87CEEB
    style EXCLUDED fill:#FFB6C1
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ Commands and Best Practices

πŸ”§ Essential Docker Commands

Build Commands

# Build multi-stage image
docker build -t multistage .

# Build with specific target stage
docker build --target installer -t build-stage .

# Build with build arguments
docker build --build-arg NODE_VERSION=18 -t multistage .
Enter fullscreen mode Exit fullscreen mode

Image Management

# List all images
docker images

# Remove specific image
docker image rm multistage

# Remove dangling images
docker image prune

# Check image size
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
Enter fullscreen mode Exit fullscreen mode

Container Operations

# Run container
docker run -d -p 3000:80 --name app-container multistage

# Check running containers
docker ps

# View container logs
docker logs 

# Execute commands in container
docker exec -it  /bin/sh
Enter fullscreen mode Exit fullscreen mode

πŸ” Debugging and Inspection Commands

# Inspect container configuration
docker inspect 

# Check container filesystem
docker exec -it  ls -la /usr/share/nginx/html

# Monitor container resource usage
docker stats 

# View container port mappings
docker port 
Enter fullscreen mode Exit fullscreen mode

πŸ“Š Performance Comparison

πŸ“ Size Comparison

graph LR
    subgraph "πŸ“Š Image Size Comparison"
        SINGLE[❌ Single-Stage200MB+]
        MULTI[βœ… Multi-Stage~50MB]

        SINGLE --> REDUCTION[75% Size Reduction]
        REDUCTION --> MULTI
    end

    subgraph "⚑ Performance Impact"
        FASTER[πŸš€ 3x Faster Pull]
        SECURE[πŸ”’ Lower Attack Surface]
        COST[πŸ’° Reduced Storage Cost]
    end

    MULTI --> FASTER
    MULTI --> SECURE
    MULTI --> COST

    style SINGLE fill:#FFB6C1
    style MULTI fill:#90EE90
    style REDUCTION fill:#FFD700
Enter fullscreen mode Exit fullscreen mode

πŸ“ˆ Benefits Breakdown

πŸ“Š Metric πŸ”΄ Single-Stage 🟒 Multi-Stage πŸ“ˆ Improvement
πŸ“¦ Image Size 200MB+ ~50MB 75% reduction
⬇️ Pull Time 30 seconds 10 seconds 3x faster
πŸš€ Startup Time 15 seconds 8 seconds 2x faster
πŸ”’ Security Vulnerabilities High Low 60% fewer
πŸ’Ύ Storage Cost High Low 75% savings

πŸ”§ Debugging and Troubleshooting

πŸ” Container Investigation Commands

# Check container logs
docker logs 

# Access container shell
docker exec -it  /bin/sh

# Inspect container details
docker inspect 
Enter fullscreen mode Exit fullscreen mode

πŸ•΅οΈ Inside Container Exploration

graph TB
    CONTAINER[🐳 Running Container]

    subgraph "πŸ“ Container Filesystem"
        ROOT[/ (root directory)]
        USR[/usr]
        SHARE[/usr/share]
        NGINX[/usr/share/nginx]
        HTML[/usr/share/nginx/html]
        FILES[πŸ“„ Static Files]

        ROOT --> USR
        USR --> SHARE
        SHARE --> NGINX
        NGINX --> HTML
        HTML --> FILES
    end

    subgraph "πŸ” Inspection Commands"
        LS[ls -la]
        CAT[cat index.html]
        PS[ps aux]
        TOP[top]
    end

    CONTAINER --> ROOT
    FILES --> LS
    FILES --> CAT

    style FILES fill:#90EE90
    style HTML fill:#87CEEB
Enter fullscreen mode Exit fullscreen mode

🚨 Common Issues and Solutions

❌ Problem πŸ” Symptom βœ… Solution
Build fails unknown instruction WORKDIR Check Dockerfile syntax
Large image size Image still 200MB+ Verify multi-stage is working
Container won't start Exit code 125 Check port conflicts
Files not found 404 errors Verify COPY paths
Permission issues Access denied Use non-root user

✨ Best Practices

🎯 Multi-Stage Build Best Practices

1. 🏷️ Use Named Stages

# βœ… Good: Named stages
FROM node:18-alpine AS installer
FROM nginx:latest AS deployer

# ❌ Bad: Unnamed stages
FROM node:18-alpine
FROM nginx:latest
Enter fullscreen mode Exit fullscreen mode

2. πŸ“¦ Choose Optimal Base Images

# βœ… Good: Lightweight base images
FROM node:18-alpine AS installer    # Small Alpine-based
FROM nginx:alpine AS deployer       # Lightweight nginx

# ❌ Bad: Heavy base images  
FROM node:18 AS installer           # Ubuntu-based (larger)
FROM nginx:latest AS deployer       # Full nginx image
Enter fullscreen mode Exit fullscreen mode

3. 🎯 Copy Only What's Needed

# βœ… Good: Selective copying
COPY --from=installer /app/build /usr/share/nginx/html

# ❌ Bad: Copying everything
COPY --from=installer /app /usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode

4. πŸ“‹ Optimize Layer Caching

# βœ… Good: Copy package files first
COPY package*.json ./
RUN npm install
COPY . .

# ❌ Bad: Copy everything first
COPY . .
RUN npm install
Enter fullscreen mode Exit fullscreen mode

πŸ”’ Security Best Practices

5. πŸ‘€ Use Non-Root User

# βœ… Good: Non-root user
FROM nginx:alpine AS deployer
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

# ❌ Bad: Running as root (default)
FROM nginx:alpine AS deployer
# No user specified - runs as root
Enter fullscreen mode Exit fullscreen mode

6. πŸ—‘οΈ Remove Unnecessary Packages

# βœ… Good: Clean up after installation
RUN apt-get update && apt-get install -y \
    package1 \
    package2 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# ❌ Bad: Leave package cache
RUN apt-get update && apt-get install -y package1 package2
Enter fullscreen mode Exit fullscreen mode

πŸš€ Performance Best Practices

7. 🎯 Use Specific Targets

# Build only specific stage for testing
docker build --target installer -t build-stage .

# Build final production image
docker build -t production-app .
Enter fullscreen mode Exit fullscreen mode

8. πŸ“¦ Multi-Architecture Support

# Support multiple architectures
FROM --platform=$BUILDPLATFORM node:18-alpine AS installer
# Build process...

FROM --platform=$TARGETPLATFORM nginx:alpine AS deployer
# Runtime setup...
Enter fullscreen mode Exit fullscreen mode

πŸ”„ Advanced Multi-Stage Patterns

9. πŸ§ͺ Testing Stage

# Build stage
FROM node:18-alpine AS installer
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Test stage
FROM installer AS tester
RUN npm test

# Production stage
FROM nginx:alpine AS deployer
COPY --from=installer /app/build /usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode

10. πŸ”€ Parallel Builds

# Base dependencies
FROM node:18-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm install

# Frontend build
FROM base AS frontend
COPY frontend/ ./
RUN npm run build:frontend

# Backend build  
FROM base AS backend
COPY backend/ ./
RUN npm run build:backend

# Final stage
FROM nginx:alpine AS final
COPY --from=frontend /app/dist /usr/share/nginx/html
COPY --from=backend /app/build /app/api
Enter fullscreen mode Exit fullscreen mode

πŸ“Š Additional Best Practices

mindmap
  root((🎯 Multi-StageBest Practices))
    πŸ—οΈ Build Optimization
      πŸ“¦ Use Alpine images
      🎯 Named stages
      πŸ“‹ Layer caching
      πŸ—‚οΈ .dockerignore file
    πŸ”’ Security
      πŸ‘€ Non-root user
      🧹 Clean package cache
      πŸ” Minimal attack surface
      🚫 No secrets in layers
    ⚑ Performance
      πŸ”„ Parallel builds
      πŸ“ Smaller final image
      πŸš€ Faster deployments
      πŸ’Ύ Reduced storage
    πŸ› οΈ Maintenance
      πŸ“ Clear documentation
      🏷️ Consistent naming
      πŸ§ͺ Testing stages
      πŸ”„ CI/CD integration
Enter fullscreen mode Exit fullscreen mode

πŸŽ“ Summary

Docker Multi-Stage Builds are a game-changing feature that revolutionizes container image optimization[1][2]. By separating build and runtime environments, you can achieve:

πŸ”‘ Key Achievements

  • πŸ“‰ 75% smaller images - From 200MB+ to ~50MB
  • πŸ”’ Enhanced security - Reduced attack surface
  • ⚑ Faster deployments - 3x faster pull times
  • πŸ’° Cost savings - Lower storage and bandwidth costs
  • 🧹 Cleaner workflow - Single Dockerfile for entire process

πŸš€ Implementation Steps

  1. πŸ—οΈ Design stages - Separate build and runtime concerns
  2. πŸ“¦ Choose base images - Use lightweight Alpine variants
  3. 🎯 Copy selectively - Only production artifacts
  4. πŸ”’ Apply security - Non-root users, clean packages
  5. πŸ“Š Monitor results - Measure size and performance improvements

Multi-stage builds represent a fundamental shift from monolithic container images to optimized, production-ready deployments. They embody the principle of "build fat, ship thin" - using all necessary tools during build time while delivering minimal, secure runtime images[3].

Start implementing multi-stage builds in your projects today to unlock significant performance gains and security improvements in your containerized applications! πŸš€

[1] https://docs.docker.com/build/building/multi-stage/
[2] https://docs.docker.com/get-started/docker-concepts/building-images/multi-stage-builds/
[3] https://docs.docker.com/build/building/best-practices/
[4] https://docs.docker.com/guides/cpp/multistage/
[5] https://dev.to/raunakgurud09/mastering-docker-multistage-builds-1e0m
[6] https://dev.to/abhay_yt_52a8e72b213be229/streamline-your-docker-images-with-multi-stage-builds-340c
[7] https://depot.dev/blog/docker-multi-stage-builds
[8] https://dev.to/citrux-digital/understanding-docker-multistage-builds-3fm7
[9] https://labs.iximiuz.com/tutorials/docker-multi-stage-builds
[10] https://dev.to/kalkwst/multi-stage-dockerfiles-3e90
[11] https://ruan.dev/blog/2022/07/31/docker-multistage-builds-for-hugo
[12] https://www.cherryservers.com/blog/docker-multistage-build
[13] https://github.com/patrickhoefler/dockerfilegraph
[14] https://docs.docker.com/build/building/multi-platform/
[15] https://overcast.blog/building-efficient-multi-stage-dockerfiles-for-production-055f34c4baed
[16] https://learn.microsoft.com/en-us/dotnet/architecture/microservices/docker-application-development-process/docker-app-development-workflow
[17] https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/
[18] https://earthly.dev/blog/docker-multistage/
[19] https://blog.devgenius.io/docker-multi-stage-build-in-detail-3d7da2948797?gi=265baab36942
[20] https://www.youtube.com/watch?v=ajetvJmBvFo

Top comments (0)