We use cookies to understand how people use Depot.
Container Builds

Optimal Dockerfile for Python with poetry

Looking for faster Python builds? We recommend using UV instead of Poetry for significantly faster dependency installation and better caching. UV supports Poetry projects natively and can speed up your builds by 10-100x while maintaining full compatibility with your pyproject.toml and poetry.lock files.

Below is an example Dockerfile that we recommend at Depot for building Docker images for Python applications that use poetry as their package manager.

# syntax=docker/dockerfile:1

FROM python:3.13-slim AS build

ENV POETRY_VERSION=2.2.1 \
    PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=100 \
    POETRY_HOME="/opt/poetry" \
    POETRY_VIRTUALENVS_IN_PROJECT=true \
    POETRY_NO_INTERACTION=1 \
    PYSETUP_PATH="/opt/pysetup" \
    VENV_PATH="/opt/pysetup/.venv"

ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"

RUN pip install "poetry==$POETRY_VERSION"

WORKDIR $PYSETUP_PATH

COPY poetry.lock pyproject.toml ./

RUN --mount=type=cache,target=/root/.cache/pypoetry \
    poetry install --no-root

COPY . .

FROM python:3.13-slim AS runtime

ENV VENV_PATH="/opt/pysetup/.venv" \
    PATH="/opt/pysetup/.venv/bin:$PATH"

RUN groupadd -g 1001 appgroup && \
    useradd -u 1001 -g appgroup -m -d /home/appuser -s /bin/bash appuser

WORKDIR /app

COPY --from=build --chown=appuser:appgroup /opt/pysetup/.venv /opt/pysetup/.venv
COPY --from=build --chown=appuser:appgroup /opt/pysetup/ ./

USER appuser

ENTRYPOINT ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

Explanation of the Dockerfile

This Dockerfile uses an optimized approach for Python applications using Poetry, featuring multi-stage builds and security optimizations.

At a high level, here are the things we're optimizing in our Docker build for a Python application with Poetry:

  • Multi-stage builds for smaller final images
  • Poetry cache mounts for dependency caching
  • Security optimizations with non-root users

Stage 1: FROM python:3.13-slim AS build

FROM python:3.13-slim AS build

ENV POETRY_VERSION=2.2.1 \
    PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=100 \
    POETRY_HOME="/opt/poetry" \
    POETRY_VIRTUALENVS_IN_PROJECT=true \
    POETRY_NO_INTERACTION=1 \
    PYSETUP_PATH="/opt/pysetup" \
    VENV_PATH="/opt/pysetup/.venv"

ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"

We start with Python 3.13 slim for a smaller base image and configure Poetry with specific environment variables:

  • POETRY_VERSION=2.2.1 pins the Poetry version for reproducible builds
  • POETRY_VIRTUALENVS_IN_PROJECT=true creates virtual environments inside the project
  • POETRY_NO_INTERACTION=1 disables interactive prompts
  • PYTHONUNBUFFERED=1 ensures logs are output in real-time

Installing Poetry

RUN --mount=type=cache,target=/root/.cache \
    pip install "poetry==$POETRY_VERSION"

We install Poetry using pip with cache mounts for efficiency.

Dependency installation

WORKDIR $PYSETUP_PATH

COPY poetry.lock pyproject.toml ./

RUN --mount=type=cache,target=/root/.cache/pypoetry \
    poetry install --no-root

We copy the Poetry configuration files and install dependencies without installing the project itself first.

Source code installation

COPY . .

After dependencies are installed, we copy the source code.

Stage 2: FROM python:3.13-slim AS runtime

FROM python:3.13-slim AS runtime

ENV VENV_PATH="/opt/pysetup/.venv" \
    PATH="/opt/pysetup/.venv/bin:$PATH"

RUN groupadd -g 1001 appgroup && \
    useradd -u 1001 -g appgroup -m -d /home/appuser -s /bin/bash appuser

WORKDIR /app

COPY --from=build --chown=appuser:appgroup /opt/pysetup/.venv /opt/pysetup/.venv
COPY --from=build --chown=appuser:appgroup /opt/pysetup/ ./

USER appuser

ENTRYPOINT ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

The runtime stage starts with a clean slim image and creates a non-root user for security. We copy the virtual environment and project files from the build stage and set proper ownership.

Understanding BuildKit Cache Mounts

Cache mounts are one of the most powerful features for optimizing Docker builds with Depot. This Dockerfile uses multiple cache mounts:

RUN --mount=type=cache,target=/root/.cache \
    pip install "poetry==$POETRY_VERSION"

RUN --mount=type=cache,target=/root/.cache/pypoetry \
    poetry install --no-root

Cache Mount Parameters Explained

  • type=cache: Specifies this is a cache mount that persists across builds.
  • target=/root/.cache: Mount point for pip's cache directory when installing Poetry.
  • target=/root/.cache/pypoetry: Mount point for Poetry's cache directory where downloaded dependencies are stored.

For more information regarding Poetry cache mounts, please visit the official Poetry documentation.