0
0
Dockerdevops~5 mins

Multiple FROM statements in Docker - Commands & Configuration

Choose your learning style9 modes available
Introduction
Sometimes you need to build a Docker image in steps, using one image to prepare files and another to run the app. Multiple FROM statements let you do this in one Dockerfile, making your images smaller and cleaner.
When you want to compile code in one image and run it in a smaller image.
When you need to separate build tools from runtime environment to reduce image size.
When you want to copy only the necessary files from a build stage to the final image.
When you want to create multi-stage builds to optimize Docker images for production.
When you want to keep your Dockerfile simple but efficient by combining build and runtime steps.
Config File - Dockerfile
Dockerfile
FROM node:18 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:1.23
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

This Dockerfile has two stages:

  • builder: Uses the Node.js image to install dependencies and build the app.
  • final stage: Uses a lightweight Nginx image to serve the built app files copied from the builder stage.

This keeps the final image small and only includes what is needed to run the app.

Commands
Builds the Docker image using the Dockerfile with multiple FROM statements to create a multi-stage build.
Terminal
docker build -t my-multi-stage-app .
Expected OutputExpected
[+] Building 12.3s (10/10) FINISHED => [builder 1/6] FROM node:18 AS builder 2.0s => CACHED [builder 2/6] WORKDIR /app 0.0s => CACHED [builder 3/6] COPY package.json package-lock.json ./ 0.0s => [builder 4/6] RUN npm install 7.5s => CACHED [builder 5/6] COPY . . 0.0s => [builder 6/6] RUN npm run build 2.5s => [final 1/3] FROM nginx:1.23 1.0s => [final 2/3] COPY --from=builder /app/build /usr/share/nginx/html 0.5s => [final 3/3] EXPOSE 80 0.0s => exporting to image 0.3s => writing image sha256:abcdef1234567890 0.0s => naming to docker.io/library/my-multi-stage-app 0.0s
Lists the Docker images to verify that the multi-stage image was created successfully.
Terminal
docker images my-multi-stage-app
Expected OutputExpected
REPOSITORY TAG IMAGE ID CREATED SIZE my-multi-stage-app latest abcdef123456 10 seconds ago 45MB
Runs the built image in a container, mapping port 8080 on the host to port 80 in the container to serve the app.
Terminal
docker run -d -p 8080:80 my-multi-stage-app
Expected OutputExpected
d1e2f3a4b5c6d7e8f9g0h1i2j3k4l5m6n7o8p9q0r1s2t3u4v5w6x7y8z9a0b1c2
-d - Run container in detached mode (in the background)
-p 8080:80 - Map port 8080 on host to port 80 in container
Checks that the app is running by requesting the homepage served by Nginx inside the container.
Terminal
curl http://localhost:8080
Expected OutputExpected
<!DOCTYPE html><html><head><title>My App</title></head><body><h1>Welcome to My App</h1></body></html>
Key Concept

If you remember nothing else from this pattern, remember: multiple FROM statements let you build in stages and copy only what you need to keep images small and efficient.

Common Mistakes
Not using AS to name build stages and then trying to copy files from unnamed stages.
Docker cannot copy files from a stage without a name, so the build fails.
Always name your build stages with AS and use that name in COPY --from=stage.
Copying unnecessary files from the build stage to the final image.
This makes the final image larger and slower to deploy.
Copy only the files needed to run the app, like build output folders.
Using a large base image for the final stage instead of a lightweight one.
This increases the image size and attack surface.
Use a minimal image like nginx or alpine for the final stage.
Summary
Use multiple FROM statements to create multi-stage Docker builds.
Name build stages with AS to copy files between stages.
Build with docker build and verify the image with docker images.
Run the container mapping ports to access the app.
Use curl or a browser to check the app is served correctly.