Build production-ready Dockerfiles for Python projects that use uv. Use when creating or refactoring Dockerfiles for reproducible installs, cache-efficient builds, bytecode compilation, small runtime images, and non-root execution. Follows the production patterns from Hynek Schlawack's article "Production-ready Python Docker Containers with uv" while staying flexible about base images and app type. Supports packaged and unpackaged applications, including web apps, workers, and CLI services. Triggers on requests like "write a Dockerfile for this Python project", "optimize this uv Dockerfile", "containerize this FastAPI/Django/Flask app", "containerize this worker", or "split this into build and runtime stages".
Use this skill to author Dockerfiles for Python projects using uv and multi-stage builds.
The default pattern is based on Hynek Schlawack's article Production-ready Python Docker Containers with uv.
python:<version>-slim for generic Python services.ubuntu:noble when system packages or org-standard base images matter.uv sync steps.build and final.RUN uv sync steps.uv cache.UV_PROJECT_ENVIRONMENT=/app and copy /app into runtime image.UV_COMPILE_BYTECODE=1.uv sync --locked for deployment builds.uv from ghcr.io/astral-sh/uv:<version>.UV_LINK_MODE=copyUV_COMPILE_BYTECODE=1UV_PYTHON_DOWNLOADS=neverUV_PROJECT_ENVIRONMENT=/appUV_PYTHON when the base image has multiple Python interpreters or when uv cannot infer the intended one cleanly.uv cache, typically /root/.cache/uv or /root/.cache.ENV.Use this as the default starting point for packaged applications:
# syntax=docker/dockerfile:1.9
FROM python:3.13-slim AS build
COPY --from=ghcr.io/astral-sh/uv:0.8.15 /uv /uvx /bin/
ENV UV_LINK_MODE=copy \
UV_COMPILE_BYTECODE=1 \
UV_PYTHON_DOWNLOADS=never \
UV_PROJECT_ENVIRONMENT=/app
WORKDIR /src
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-dev --no-install-project
COPY . /src
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-dev --no-editable
FROM python:3.13-slim AS final
ENV PATH="/app/bin:$PATH"
STOPSIGNAL SIGINT
RUN groupadd --system app && useradd --system --gid app --home-dir /app app
COPY --from=build --chown=app:app /app /app
USER app
WORKDIR /app
CMD ["python", "-m", "your_package"]
Keep the following adaptation rules in mind:
uv sync step and copy the source into the runtime image after copying /app.ENTRYPOINT script and keep STOPSIGNAL SIGINT.python:<version>-slim, install the exact runtime Python packages explicitly and set UV_PYTHON if needed.Pick the startup command that matches the project type.
EXPOSE 8000
CMD ["uvicorn", "your_package.main:app", "--host", "0.0.0.0", "--port", "8000"]
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "your_project.wsgi:application"]
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "your_package.wsgi:app"]
CMD ["python", "-m", "your_package.worker"]
ENTRYPOINT ["python", "-m", "your_package.cli"]
Use JSON-array syntax for CMD and ENTRYPOINT.
Run this checklist before finalizing output:
uv is copied from the official image.uv.UV_PROJECT_ENVIRONMENT=/app is set and /app is copied into the runtime image.PATH includes /app/bin when executables live in the project environment.STOPSIGNAL SIGINT.EXPOSE for network services..dockerignore that excludes VCS data, caches, build artifacts, and local virtualenvs.When generating a Dockerfile for a user:
.dockerignore suggestion when missing.