Slim base and uv

A naive Dockerfile bakes the build toolchain, tests, and cached wheels into the final image. You ship 1.2 GB, pull times are painful, and the attack surface is huge. A multi-stage build splits dependency resolution from runtime so the final image only carries what the app actually needs to run.

Dockerfile
dockerfile
# syntax=docker/dockerfile:1.7

# ---------- Stage 1: builder ----------
FROM python:3.11-slim AS builder

COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

ENV UV_LINK_MODE=copy \
    UV_PROJECT_ENVIRONMENT=/app/.venv

COPY pyproject.toml ./
RUN uv sync --no-dev

The builder stage pulls uv from its official image and resolves the project dependencies into a self-contained .venv at /app/.venv. Skipping dev dependencies keeps the virtualenv to what the app actually needs at runtime.

Two stages, one image

Everything heavy stays in the builder. Only the venv and code land in runtime.

Quiz: Quiz

Loading practice…