Multi-Stage Builds In Docker: Save Image Size And Improve Security
Docker multi-stage builds help developers create smaller, cleaner, and more secure images by separating the build environment from the final runtime. In this post, you’ll learn what multi-stage builds in Docker are and how to use them effectively.
Why Use Multi-Stage Builds in Docker?
Normally, when you build an image that compiles code (e.g., with gcc, npm, or go build), those tools and dependencies stay in the final image — even if they’re no longer needed at runtime.
This leads to:
- 🚫 Unnecessary bloat
- 🛡️ Higher security risks
- 🐌 Slower deploys
Multi-stage builds solve this by using multiple FROM statements in a single Dockerfile — copying only the final output from the build phase into a clean runtime environment.
Example: Python App Using Poetry for Dependency Management
Let’s say you have a simple Python app that uses Poetry for dependency management.
Create a file named pyproject.toml:
[tool.poetry]
name = "hello-docker"
version = "0.1.0"
description = ""
authors = ["You"]
[tool.poetry.dependencies]
python = "^3.11"
[tool.poetry.scripts]
hello = "app:main"
Next, create app.py:
def main():
print("Hello from a Python multi-stage Docker build!")
if __name__ == "__main__":
main()
Dockerfile with Multi-Stage Build
# Stage 1: Build using Poetry
FROM python:3.11-slim AS builder
RUN pip install poetry
WORKDIR /app
COPY pyproject.toml .
COPY app.py .
# Install only dependencies, skip installing current project
RUN poetry config virtualenvs.create false \
&& poetry install --only main --no-root --no-interaction
# Stage 2: Clean runtime image
FROM python:3.11-alpine
WORKDIR /app
COPY --from=builder /app /app
CMD ["python", "app.py"]
Build and Run
docker build -t python-multistage .
docker run --rm python-multistage

Expected output:
Hello from a Python multi-stage Docker build!

Size Comparison (Approximate)
| Method | Image Size |
| Without multi-stage | ~300MB |
| With multi-stage | ~30MB 🧨 |
Benefits Recap
- 🧼 Clean final images — no compilers or build tools
- 📦 Smaller image sizes = faster CI/CD and deploys
- 🔐 Lower attack surface = better security
- 👏 Easier to maintain consistent build vs. runtime environments
Use Cases
- Compiling code (Go, Node.js, Java, Rust)
- Installing & optimizing frontend builds (
npm run build) - Packaging Python apps with
pipbut leaving out the cache
Multi-stage builds are one of Docker’s most powerful and underutilized features. They help you build production-grade containers that are both efficient and secure. Once you try them, you’ll never go back to bulky images.
You can read more useful articles like Dockerfile Explained: How to Build Custom Docker Images.
Follow us for the more helpful posts!
We hope this is a useful post for you.