Optimize Node.js Images with Multi-Stage Builds
Multi-stage builds separate your build environment from your final runtime. This lets you use heavy tools to build your Node.js app, then ship only the lean production code, drastically reducing image size and attack surface.
Why it exists
Default Dockerfiles for Node.js applications often create bloated, insecure, and slow images. They bundle build tools, development dependencies, and source code into the final production image. This increases the attack surface and slows down deployment pipelines due to large image sizes.
The mental model
A multi-stage build is like having a separate workshop to assemble furniture. In the first stage (the workshop), you use all your heavy tools and read the full instruction manual (the Node SDK, devDependencies, compilers). Once the furniture is built, you move only the finished piece into your home (the final image), leaving all the tools, scraps, and manuals behind. The result is a clean, minimal final environment.
How it works
A single Dockerfile can contain multiple FROM instructions. Each FROM starts a new build stage, which can be named (e.g., FROM node:18 AS builder). A later stage can then copy files from a previous one using the COPY --from=<stage_name> flag. For a Node.js app, a 'builder' stage installs all dependencies, including devDependencies, to build or transpile the code. A final 'production' stage starts from a clean, minimal Node.js image and copies only the necessary application code and production dependencies from the builder stage. Only the final stage is saved as the resulting image.
When to use it
Use multi-stage builds for virtually all production Node.js applications destined for containers. The benefits are significant: smaller image sizes (often by 50-90%), improved security by excluding build tools like compilers and shells, and faster CI/CD pipeline performance due to smaller artifacts being pushed and pulled.
When not to use it
There are very few reasons to avoid multi-stage builds. For a quick, temporary development container where image size is completely irrelevant, a single-stage build might be marginally faster to write. However, for any code that will be shared or deployed, using a multi-stage build is a best practice.
One canonical example
A typical Dockerfile first defines a 'builder' stage starting from a full Node image. It copies package.json and package-lock.json, then runs npm install to leverage Docker's layer caching. Only then does it copy the rest of the source code and run a build script if needed. The second, final stage starts from a minimal base image like node:18-alpine. It copies package*.json again and runs npm install --only=production. Finally, it uses COPY --from=builder to pull the built application code from the first stage. The final image contains only the runtime, production dependencies, and the application itself.
Interview question
What is the primary advantage of using multi-stage builds for Node.js Docker images?
- a.It allows developers to use different Node.js versions for building and running the application.
- b.It significantly reduces the final image size and improves security by removing unnecessary build tools.Correct
- c.It ensures that all development dependencies are available in the production environment for easier debugging.
- d.It speeds up the initial Docker image build process by parallelizing dependency installation.
Why? this is the answer
Multi-stage builds primarily reduce the final Docker image size and enhance security by separating the build environment from the runtime, thus excluding heavy build tools and development dependencies. Option C is incorrect as multi-stage builds aim to remove development dependencies from the final image.
Just read this? Test yourself on what you have been reading.
Read the original → docs.docker.com
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on docker — each one lists the topics its interview covers.
See open roles