Иногда полезно ставить зависимости в несколько шагов.
Например, чтобы лучше работал кэш слоев при сборке Docker-образа.
Сначала ставим только зависимости.
Потом копируем проект и ставим уже сам проект.
Зачем делить на два шага?
Docker собирает образ слоями: если слой закэширован, он не пересобирается, пока не изменились входные файлы.
Если отделить установку зависимостей от установки проекта:
▪️Если меняется только main.py, Docker переиспользует закэшированный слой с зависимостями (быстрее)
▪️Если меняется только pyproject.toml, Docker пересобирает слои начиная с этого места (и это правильно, потому что зависимости поменялись)
Без такого разделения любое изменение кода заставит заново переустанавливать все зависимости.
# Install the project's dependencies using the lockfile and settings
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-install-project
# Then, add the rest of the project source code and install it
# Installing separately from its dependencies allows optimal layer caching
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked
👉 @PythonPortal
