How to use uv with VS Code devcontainers
A devcontainer hands every teammate the same Python interpreter and the same locked dependencies. uv makes that hand-off cheap: a single uv sync --locked reads uv.lock and installs the resolved graph in seconds, on every machine.
This guide configures a VS Code devcontainer that uses uv to materialize the project’s virtual environment inside the container, points VS Code at the in-container interpreter, and uses the lockfile to keep team environments in sync.
Note
Devcontainer support in VS Code requires the Dev Containers extension (ms-vscode-remote.remote-containers) and a working Docker installation. GitHub Codespaces uses the same devcontainer.json format with no Docker install on the local machine.
Add a devcontainer.json with the official uv image
Create .devcontainer/devcontainer.json and .devcontainer/Dockerfile at the repository root. The Dockerfile uses Astral’s prebuilt uv image so uv and the Python toolchain are already installed:
FROM ghcr.io/astral-sh/uv:python3.13-trixie-slim
ENV UV_LINK_MODE=copy \
UV_COMPILE_BYTECODE=1 \
UV_PROJECT_ENVIRONMENT=/workspaces/.venv
WORKDIR /workspacesUV_LINK_MODE=copy silences cross-filesystem warnings between the cache and the project, UV_COMPILE_BYTECODE=1 precompiles .pyc files so the first import after a rebuild is not slow, and UV_PROJECT_ENVIRONMENT puts the venv at a stable absolute path that VS Code can reference.
The matching devcontainer.json:
{
"name": "uv-python",
"build": { "dockerfile": "Dockerfile" },
"postCreateCommand": "uv sync --locked --all-groups",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"charliermarsh.ruff"
],
"settings": {
"python.defaultInterpreterPath": "/workspaces/.venv/bin/python",
"python.terminal.activateEnvironment": false
}
}
}
}postCreateCommand runs once after the container is built. The flag choice matters more than it looks:
uv sync --lockedre-resolvespyproject.tomland fails if the lockfile would change. Right for a team devcontainer: if a teammate forgot to commit a regenerated lockfile, the rebuild fails loudly instead of silently producing a different environment.uv sync --frozeninstalls whatever the lockfile contains without checking it againstpyproject.toml. Faster (no resolution step), but a stale lockfile installs silently. Right for production Docker images (see How to use uv in a Dockerfile).
--all-groups installs every group declared under [dependency-groups] in pyproject.toml, so dev tools like pytest and Ruff land in the container alongside runtime deps.
python.terminal.activateEnvironment is set to false because uv manages activation through uv run. If the Python extension also tries to activate the venv, every new terminal prints a benign but noisy activation script. For a deeper walk-through of the Python and Ruff extensions, see How to configure VS Code for a uv project.
Point VS Code at the in-container venv
The Python extension auto-discovers .venv/ at the workspace root, but a devcontainer mounts the workspace at /workspaces/<project-name> and the venv lives at /workspaces/.venv (the path that UV_PROJECT_ENVIRONMENT sets in the Dockerfile). Setting python.defaultInterpreterPath to that absolute path tells the extension where to look on first launch.
Tip
If VS Code shows “Python interpreter not found” after the container starts, run uv sync --locked in the integrated terminal and reload the window with Cmd+Shift+P → Developer: Reload Window. The interpreter does not exist until uv sync has populated /workspaces/.venv.
For projects that use multiple Python versions or workspace members, override the interpreter per-folder in .vscode/settings.json instead of in devcontainer.json so each member can pin its own venv.
Run the same setup in GitHub Codespaces
GitHub Codespaces reads the same .devcontainer/ directory. Push the branch, click Code → Codespaces → Create codespace on main in the GitHub UI, and Codespaces builds the container in the cloud and connects a browser-based VS Code to it. No local Docker required.
Codespaces enforces two extra constraints worth knowing:
- The base image must be available to GitHub’s runners. Public images on
ghcr.io,mcr.microsoft.com, and Docker Hub work without configuration. - Post-create commands run with a 60-minute timeout.
uv sync --lockedfinishes in a few seconds on most projects, so this is rarely a concern.
Pin the uv version
ghcr.io/astral-sh/uv:python3.13-trixie-slim floats to the latest uv release. For reproducible team setups, pin to a specific uv version:
FROM ghcr.io/astral-sh/uv:0.11.11-python3.13-trixie-slimThis guarantees every teammate gets the same uv binary, not just the same Python version. Bump the pin in a single commit when a new uv release ships features the team wants.
Troubleshooting
uv sync fails with “no project found”: The WORKDIR in the Dockerfile must match where the workspace is mounted, or postCreateCommand runs in the wrong directory. Set WORKDIR /workspaces in the Dockerfile, since VS Code mounts the host workspace under /workspaces/<project-name>.
VS Code uses the wrong interpreter after rebuild: Open the Command Palette and run Python: Clear Cache and Reload Window. Stale interpreter cache survives container rebuilds in some VS Code versions.
“externally-managed-environment” error from uv pip install: A devcontainer running uv pip install outside a venv hits Debian’s externally-managed-environment protection. Use uv sync or uv add against the project’s venv instead.
Permission errors writing to /workspaces/.venv: When mixing the official uv image (root by default) with a Microsoft Python image’s vscode user, the venv ends up owned by the wrong user. Either stay on one image family or set "remoteUser": "root" in devcontainer.json for development containers where root is acceptable.
Learn More
- Dev Containers documentation describes the
devcontainer.jsonschema in full. - GitHub Codespaces documentation covers the cloud-hosted devcontainer flow.
- uv Docker integration guide lists every published uv image variant and recommended environment variables.
va-h/devcontainers-features/uvadds uv to Microsoft’smcr.microsoft.com/devcontainers/pythonimage as a feature, for teams already standardized on that base image.- How to configure VS Code for a uv project covers the equivalent setup without devcontainers.
- How to use uv in a Dockerfile covers production image patterns (multi-stage builds, BuildKit cache mounts,
--frozensemantics) that complement the development setup in this guide.