Problem
The Dockerfile leaves build/download caches inside the image layers, permanently inflating every project image:
- uv cache:
uv tool install semgrep + uv python install 3.13 download wheels into /root/.cache/uv (root stage) — semgrep alone is a 710 MB layer; a chunk of that is uv's download cache which is never cleaned.
- apt lists: cleaned in the main apt layer (
rm -rf /var/lib/apt/lists/*) but the toolchain block runs sudo apt-get update and cleans only at the very end of the loop (sudo apt-get clean && sudo rm -rf /var/lib/apt/lists/*) — if the if is entered, ok; but caches from go install/cargo install are never removed.
- Go build cache:
go install ...gosec@latest leaves $HOME/.cache/go-build + module cache in the image (~200–500 MB).
- Cargo:
cargo install cargo-audit --locked compiles from source; ~/.cargo/registry + build artifacts can add 1+ GB to the image.
- npm: nodejs is installed via apt; npm itself isn't used at build time, but if a project-setup.sh runs npm, the cache persists (minor).
Proposal
Add a cache-cleanup layer right before the final WORKDIR, and use build-time-only caches where possible:
# Remove build-time caches so they never land in the image.
RUN rm -rf /root/.cache/uv /home/vscode/.cache/uv \
&& rm -rf /home/vscode/.cargo/registry /home/vscode/.cargo/target /home/vscode/.cache/go-build \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*.deb \
&& rm -rf /tmp/*
Better: use BuildKit cache mounts so caches never enter the layer at all:
RUN --mount=type=cache,target=/root/.cache/uv uv tool install semgrep
RUN --mount=type=cache,target=/var/cache/apt apt-get update && apt-get install -y ...
(--mount=type=cache keeps downloads in the builder cache — which already exists at 45 GB on this host — and out of the image.)
Expected saving: 500 MB – 1.5 GB per image depending on toolchains.
Files
templates/devcontainer/Dockerfile.tmpl — uv/apt/go/cargo steps
Acceptance criteria
docker history <image> shows no >100 MB layer from uv/cargo/go caches.
docker run --rm <image> du -sh /root/.cache /home/vscode/.cargo /home/vscode/.cache → all near-zero.
uv tool run semgrep --version still works after cleanup (semgrep is installed into UV_TOOL_DIR=/opt/uv/tools, not the cache).
Problem
The Dockerfile leaves build/download caches inside the image layers, permanently inflating every project image:
uv tool install semgrep+uv python install 3.13download wheels into/root/.cache/uv(root stage) — semgrep alone is a 710 MB layer; a chunk of that is uv's download cache which is never cleaned.rm -rf /var/lib/apt/lists/*) but the toolchain block runssudo apt-get updateand cleans only at the very end of the loop (sudo apt-get clean && sudo rm -rf /var/lib/apt/lists/*) — if theifis entered, ok; but caches fromgo install/cargo installare never removed.go install ...gosec@latestleaves$HOME/.cache/go-build+ module cache in the image (~200–500 MB).cargo install cargo-audit --lockedcompiles from source;~/.cargo/registry+ build artifacts can add 1+ GB to the image.Proposal
Add a cache-cleanup layer right before the final
WORKDIR, and use build-time-only caches where possible:Better: use BuildKit cache mounts so caches never enter the layer at all:
(
--mount=type=cachekeeps downloads in the builder cache — which already exists at 45 GB on this host — and out of the image.)Expected saving: 500 MB – 1.5 GB per image depending on toolchains.
Files
templates/devcontainer/Dockerfile.tmpl— uv/apt/go/cargo stepsAcceptance criteria
docker history <image>shows no >100 MB layer from uv/cargo/go caches.docker run --rm <image> du -sh /root/.cache /home/vscode/.cargo /home/vscode/.cache→ all near-zero.uv tool run semgrep --versionstill works after cleanup (semgrep is installed intoUV_TOOL_DIR=/opt/uv/tools, not the cache).