Skip to main content
Containerizing a Node.js web application often involves separate build and packaging steps. Docker’s multi-stage builds streamline this process into a single, maintainable Dockerfile that produces smaller, more consistent images.

1. Local Build and Basic Containerization

First, you might compile your app locally:
This generates a dist/ folder with your production assets. To serve it via Nginx, you could write:
Build and run:

Drawbacks of This Approach

2. Using a Separate Builder Image

To ensure repeatable builds, move compilation into its own container:
You still use the production Dockerfile from before. Then:
Now you have:
  1. builder image with dist/
  2. my-app image ready to serve via Nginx
Manually extracting artifacts involves creating temporary containers and copying files. This adds complexity and slows down CI/CD pipelines.

3. Simplifying with Multi-Stage Builds

Multi-stage builds merge builder and final stages:
Just build once:
What happens:
  1. builder stage installs dependencies and compiles into dist/.
  2. final stage pulls only the built assets into a minimal Nginx image.

3.1 Using Numeric Stage References

Instead of names, you can refer to stages by index:
Using named stages (e.g., AS builder) improves readability in complex Dockerfiles.

3.2 Building a Specific Stage

For debugging or CI-cache purposes, target only the build stage:

4. Benefits of Multi-Stage Builds

The image is a slide titled "Multi-Stage Builds" that lists benefits such as optimizing Dockerfiles, reducing image size, avoiding multiple Dockerfiles, and eliminating intermediate images.

Watch Video