A multistage Dockerfile is a feature introduced in Docker to address the challenge of creating lean and efficient container images Traditionally, Docker images used to contain all the dependencies, libraries, and tools required to run an application, leading to bloated images that consume unnecessary disk space and hence increase the deployment times
Now Multistage builds allow developers to build multiple intermediate images within a single Dockerfile, and each intermediate image serves a specific purpose in the build process.

Multistage Dockerfile Working
In a multistage Dockerfile, developers define multiple build stages, each encapsulating a specific set of instructions and dependencies. These stages can be named and referenced within the Dockerfile, enabling seamless communication between them.
- Basically, the first stage of creating a multistage Dockerfile is dedicated to building the application code, while subsequent stages focus on packaging the application and preparing it for runtime.
- Intermediate images that are generated in earlier stages are discarded just after their purpose is served, resulting in a final production image that contains only the essential components required to run the application.

Use Multi-Stage Builds
# Code template to get you started For Multistage Dockerfile
# Build stage with development tools
FROM maven:3.5-jdk-8 as build
WORKDIR /app
COPY . .
RUN mvn clean package
#FInal Stage
FROM tomcat:8.0.20-jre8
COPY --from=build /app/target/maven-web-app*.war /usr/local/tomcat/webapps/maven-web-application.warExplanation Of The Code
Build Stage (build):FROM maven:3.5-jdk-8 as build: This line designates the official Maven image with JDK 8 installed as the basis image for the build stage.WORKDIR /app: Sets the Docker container's working directory to /app.COPY . .: Moves each file from the current directory (which includes the Dockerfile) to the /app directory of the container.RUN mvn clean package: Performs out the project's cleanup and WAR file packaging using the Maven command. The Maven project is assumed to be in the root directory with this command.
FROM maven:3.5-jdk-8 as build: This line designates the official Maven image with JDK 8 installed as the basis image for the build stage.WORKDIR /app: Sets the Docker container's working directory to /app.COPY . .: Moves each file from the current directory (which includes the Dockerfile) to the /app directory of the container.RUN mvn clean package: Performs out the project's cleanup and WAR file packaging using the Maven command. The Maven project is assumed to be in the root directory with this command.Final Stage:FROM tomcat:8.0.20-jre8: Use the official Tomcat image with JRE 8 installed as the basis image for the final step.COPY --from=build /app/target/maven-web-app*.war /usr/local/tomcat/webapps/maven-web-application.war: Copies the generated WAR file from the build step into the final image's Tomcat webapps directory (/usr/local/tomcat/webapps/). The file is being copied from the previous build stage, according to by the --from=build flag. To take into account version numbers or other variations in the WAR file name, use the wildcard pattern maven-web-app*.war.
FROM tomcat:8.0.20-jre8: Use the official Tomcat image with JRE 8 installed as the basis image for the final step.COPY --from=build /app/target/maven-web-app*.war /usr/local/tomcat/webapps/maven-web-application.war: Copies the generated WAR file from the build step into the final image's Tomcat webapps directory (/usr/local/tomcat/webapps/). The file is being copied from the previous build stage, according to by the --from=build flag. To take into account version numbers or other variations in the WAR file name, use the wildcard pattern maven-web-app*.war.


Name Your Build Stages
The AS keyword in the FROM instruction lets us to assign names to the construction phases. In spite of keeping everything clear, this naming makes sure that directives like COPY remain intact if the Dockerfile is later reorganized. Kindly refer to the command below for your reference.
FROM maven:3.5-jdk-8 as buildStop At A Specific Build Stage
When getting the Docker image, we may provide the target build stage with the --target flag to stop at that particular point. This allows you to halt the build process as certain points without building the stages that followed.
docker build --target build -t your-image-name .The parameter --target build defines the 'build' target build stage. This tells Docker to terminate the build process once the commands provided in the 'build' stage have been performed out.-t your-image-nameassigns a tag (name) to the Docker image..indicates the current directory where the Dockerfile is located.
Distroless Images in Multi-Stage Dockerfiles
Distroless images are lightweight container images provided by Google that include only the application runtime dependencieswithout a package manager, shell, or OS utilities. This makes them significantly smaller and more secure than traditional base images like Ubuntu or Debian.
In the context of multi-stage Dockerfiles:
- Usage in Final Stage: Developers often build and compile their applications in a full development environment (e.g.,
maven:3.5-jdk-8,golang:1.x) and then copy only the compiled binaries or artifacts into a distroless runtime image. - Security Advantage: By excluding shells and package managers, distroless images reduce the attack surface, making it harder for attackers to exploit the container.
- Efficiency: They result in smaller, faster, and more efficient production images.
- Best Practice: Use a distroless image in the final stage for runtime, while using heavier base images only for building.
Use An External Image As A Stage
The FROM instruction is employed to reference an image from a Docker registry or repository when employing an external image as a stage in a Dockerfile. You can reuse pre-built images as stages in your multi-stage builds through this approach.
# Build stage with development tools
FROM maven:3.5-jdk-8 as build
WORKDIR /app
COPY . .
RUN mvn clean package
#FInal Stage
FROM tomcat:8.0.20-jre8
COPY --from=build /app/target/maven-web-app*.war /usr/local/tomcat/webapps/maven-web-application.warCOPY --from=build /app/target/maven-web-app*.war /usr/local/tomcat/webapps/maven-web-application.war: Copies the WAR file generated during the build stage from the build stage's /app/target/ directory to the stage's /usr/local/tomcat/webapps/ directory. Through doing this, the Maven-based web application has been properly configured on the Tomcat server.
Differences Between Legacy Builder And BuildKit
- Performance
- Legacy Builder: Builds are slower and less efficient.
- BuildKit: Faster builds with optimized layer management and parallel execution.
- Caching
- Legacy Builder: Limited caching; often rebuilds unchanged steps.
- BuildKit: Advanced caching with fine-grained control and better reuse of layers.
- Parallel Execution
- Legacy Builder: Runs instructions sequentially.
- BuildKit: Can execute independent steps in parallel to save time.
- Output Control
- Legacy Builder: Only supports standard Docker image output.
- BuildKit: Can export multiple formats (OCI, Docker) or just build artifacts.
- Secrets & SSH Support
- Legacy Builder: No built-in support.
- BuildKit: Securely mounts secrets and SSH keys during builds.
- Advanced Features
- Legacy Builder: Limited to basics like multi-stage builds.
- BuildKit: Adds cache mounts, inline builds, custom frontends, and more.
Necessary Commands Required For Multi-Stage Dockerfile
- FROM image:tag – Defines the base image for the current stage. (Stage-specific: Yes)
- AS name – Assigns a name to the current stage. (Stage-specific: Yes)
- WORKDIR path – Sets the working directory for subsequent commands. (Stage-specific: No)
- COPY source destination – Copies files/directories from context or a previous stage. (Stage-specific: No)
- RUN command – Executes shell commands. (Stage-specific: No)
- CMD ["command", "arg1", ...] – Sets the default command when the container starts. (Stage-specific: No)
- USER user – Sets the user account for container processes. (Stage-specific: No)
- EXPOSE port – Specifies ports that the container listens on. (Stage-specific: No)
- ENV KEY=VALUE – Defines environment variables accessible in the container. (Stage-specific: No)
- LABEL key=value – Adds metadata labels to the image. (Stage-specific: No)
- --from=stage – Specifies the source stage for copying files. (Stage-specific: Yes)
Realtime Use Case Examples
Stream Processing And Analytics
An application ingesting and analyzing data streams like tweets or stock prices in real-time To handle this efficiently, we require leverage multi-stage builds:
- Build stage: Installing libraries for message queuing, like RabbitMQ or Apache Kafka, which are just needed for testing and development, occurs at this step.
- Runtime stage: Only the application code and requirements required to process data streams are provided in this level. Removing superfluous libraries leads in a substantially smaller size and a quicker initialization.
Best Practices For Multistage Dockerfile
- Identify Build Stages: Analyze the application requirements and identify distinct build stages based on compilation, testing, packaging, and deployment.
- Minimize Dependencies: Install only the necessary dependencies and libraries in each build stage to keep the image size to a minimum.
- Optimize Layering: Utilize Docker's layer caching mechanism to optimize layering and maximize build efficiency.
- Leverage Official Images: Whenever possible, leverage official Docker images as base images for your build stages to ensure reliability and security.
- Test and Iterate: Its great habit to Continuously test and iterate on your multistage Dockerfiles.