0
0
Dockerdevops~5 mins

Multi-stage for different environments in Docker - Commands & Configuration

Choose your learning style9 modes available
Introduction
Building Docker images for different environments like development and production can be slow and create large files. Multi-stage builds let you create smaller, faster images by separating steps for each environment in one file.
When you want a fast image for development with debugging tools included.
When you need a small, secure image for production without extra files.
When you want to avoid repeating similar build steps for different environments.
When you want to keep your Dockerfile clean and easy to maintain.
When you want to reduce the size of your final Docker image to save space.
Config File - Dockerfile
Dockerfile
FROM node:18 AS base
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .

FROM base AS development
ENV NODE_ENV=development
CMD ["npm", "run", "dev"]

FROM base AS production
ENV NODE_ENV=production
RUN npm run build
CMD ["npm", "start"]

This Dockerfile has three stages:

  • base: installs dependencies and copies source code, shared by both environments.
  • development: uses base, sets environment to development, and runs the app with live reload.
  • production: uses base, sets environment to production, builds the app, and runs the optimized version.

This keeps images small and environment-specific.

Commands
Builds the Docker image using the development stage for a fast, debug-friendly environment.
Terminal
docker build --target development -t my-app-dev .
Expected OutputExpected
[+] Building 12.3s (10/10) FINISHED => [base 1/6] FROM docker.io/library/node:18@sha256:... => CACHED [base 2/6] WORKDIR /app => CACHED [base 3/6] COPY package.json package-lock.json ./ => CACHED [base 4/6] RUN npm install => CACHED [base 5/6] COPY . . => [development 6/6] ENV NODE_ENV=development => exporting to image => => exporting layers => => writing image sha256:... Successfully built sha256:... Successfully tagged my-app-dev:latest
--target - Specifies which build stage to use
-t - Names the image
Runs the development image, exposing port 3000 to access the app in the browser.
Terminal
docker run --rm -p 3000:3000 my-app-dev
Expected OutputExpected
> my-app@dev > next dev ready - started server on http://localhost:3000
--rm - Removes container after it stops
-p - Maps container port to host port
Builds the Docker image using the production stage for a small, optimized environment.
Terminal
docker build --target production -t my-app-prod .
Expected OutputExpected
[+] Building 15.7s (11/11) FINISHED => [base 1/6] FROM docker.io/library/node:18@sha256:... => CACHED [base 2/6] WORKDIR /app => CACHED [base 3/6] COPY package.json package-lock.json ./ => CACHED [base 4/6] RUN npm install => CACHED [base 5/6] COPY . . => [production 6/7] ENV NODE_ENV=production => [production 7/7] RUN npm run build > my-app@build > next build > exporting to image > => exporting layers > => writing image sha256:... Successfully built sha256:... Successfully tagged my-app-prod:latest
--target - Specifies which build stage to use
-t - Names the image
Runs the production image, exposing port 8080 to access the optimized app.
Terminal
docker run --rm -p 8080:3000 my-app-prod
Expected OutputExpected
> my-app@start > next start ready - started server on http://localhost:3000
--rm - Removes container after it stops
-p - Maps container port to host port
Key Concept

If you remember nothing else from this pattern, remember: multi-stage builds let you create different environment images efficiently in one Dockerfile.

Common Mistakes
Not using the --target flag when building, so Docker builds all stages instead of just one.
This makes the build slower and the image larger than needed for the environment.
Always use --target with the stage name to build only the needed environment.
Copying unnecessary files in all stages, including development tools in production.
This increases the image size and can expose sensitive files in production.
Use multi-stage builds to copy only what each environment needs.
Running the wrong image tag for the environment, like running the production image during development.
You lose debugging features and live reload, slowing development.
Tag images clearly and run the correct one for each environment.
Summary
Use multi-stage Dockerfiles to separate build steps for development and production.
Build images with the --target flag to choose the environment stage.
Run the correct image tag to get the right environment behavior and size.