# Reducing Python Docker Image Size with Multi-Stage Builds

One of the most effective ways to reduce the size of a Docker image is using **multi-stage builds**. This technique allows you to use a heavy image with all the necessary build tools (compilers, headers) to install dependencies, and then copy only the necessary artifacts (installed packages) to a lightweight "runner" image.

## The Problem

When you install Python packages (like `numpy`, `pandas`, or `psycopg2`), `pip` often needs to compile C code. This requires system tools like `gcc` and `python3-dev`.

If you install these tools in your final image, it becomes unnecessarily large and increases the security attack surface.

## The Solution: Multi-Stage Dockerfile

Here is a pattern that separates the **build environment** from the **runtime environment**.

```dockerfile
# __________ STAGE 1: BUILDER __________
# We use a slim image, but we will install build tools here.
FROM python:3.11-slim as builder

WORKDIR /app

# 1. Install system dependencies required for building Python packages
# (e.g., gcc, libpq-dev). These won't make it to the final image.
RUN apt-get update && apt-get install -y \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# 2. Create a virtual environment to isolate our packages
RUN python -m venv /opt/venv

# 3. Activate the venv for the following commands
ENV PATH="/opt/venv/bin:$PATH"

# 4. Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt


# __________ STAGE 2: FINAL __________
# We start fresh with a clean, lightweight image.
FROM python:3.11-slim

WORKDIR /app

# 1. Copy the virtual environment from the 'builder' stage
# This is the magic step. We get the compiled packages without the compiler tools.
COPY --from=builder /opt/venv /opt/venv

# 2. Activate the venv
ENV PATH="/opt/venv/bin:$PATH"

# 3. Copy application code
COPY . .

# 4. Run
CMD ["python", "main.py"]
```

## Key Concepts

1.  **`as builder`**: Names the first stage so we can reference it later.
2.  **Virtual Environment (`/opt/venv`)**: We install everything into a specific folder. This makes it incredibly easy to copy *just* the dependencies to the next stage.
3.  **`COPY --from=builder`**: Copies files from the previous stage instead of the host machine.
4.  **Result**: Your final image contains only Python, your code, and the compiled libraries. It does not contain `gcc`, `apt` caches, or build artifacts.

[[programming/python/docker-python]]