Skip to content
GitHub
Build Errors

Docker layer caching for uv workspace monorepos

Docker layer caching for uv workspace monorepos

Severity: P3 (build ergonomics; correctness unaffected) · Applies to: uv workspace monorepos with Docker images Related: ADR-049 — Container strategy

Problem

In a uv workspace monorepo, a naive Dockerfile runs uv sync after copying all source files. Any change to any .py file invalidates the dependency layer, causing a full re-download of all packages on every build (~60s+).

Symptoms:

  • Every docker build re-downloads all pip packages
  • CI builds are slow even for small code changes
  • No layer cache hits after the COPY . . step

Root Cause

Docker layers are invalidated when any file in a COPY command changes. If you copy source code before running uv sync, the dependency install layer is never cached.

Solution

Two-phase uv sync — install third-party deps first (cached), then link workspace packages (fast).

FROM python:3.14-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
WORKDIR /app
# Phase 1: Copy ONLY dependency manifests (changes rarely)
COPY pyproject.toml uv.lock .python-version ./
COPY packages/core/pyproject.toml packages/core/pyproject.toml
COPY apps/api/pyproject.toml apps/api/pyproject.toml
# Install deps without linking workspace packages
RUN uv sync --package spectral-api --frozen --no-install-workspace --no-dev
# Phase 2: Copy source code (changes often)
COPY packages/core/src/ packages/core/src/
COPY apps/api/src/ apps/api/src/
# Link workspace packages (fast — just symlinking)
RUN uv sync --package spectral-api --frozen --no-dev

Key flags

FlagPurpose
--no-install-workspaceSkip local package linking; only install remote deps
--frozenUse uv.lock exactly; no version negotiation
--no-devSkip dev dependencies for production images
--package <name>Only sync deps for one workspace member

Performance

ScenarioWithout patternWith pattern
First build~60s~60s
Source-only change~60s~2s
Dependency change~60s~60s

Prevention

  • Always separate dependency installation from source code copying in Dockerfiles
  • Apply the same principle in CI: install deps in a cached step before copying test code
  • This pattern is not in uv docs — document it for your team