uv sync --no-dev: install a project without its dev dependencies
- tool
- uv
- command
- uv sync
- flag
- --no-dev, --only-dev, --group, --no-group, --all-groups
- default
- the dev dependency group is included
uv sync --no-dev installs the project's runtime dependencies from uv.lock and leaves out the dev dependency group (test runners, linters, type checkers). Because uv sync is exact, packages from the dev group that are already in .venv are removed. It is the usual command for production images and deploys; add --locked so the build fails when uv.lock is out of date. uv run --no-dev applies the same selection to a single run.
Full sync and --no-dev
six is a runtime dependency, humanize a dev dependency:
cat > pyproject.toml <<'EOF'
[project]
name = "demo"
version = "0.1.0"
requires-python = ">=3.9"
dependencies = ["six==1.16.0"]
[dependency-groups]
dev = ["humanize==4.11.0"]
EOF
uv sync -q
echo "--- uv sync"
uv pip list -q --format=freeze
uv sync -q --no-dev --locked
echo "--- uv sync --no-dev --locked"
uv pip list -q --format=freezeOutput
--- uv sync humanize==4.11.0 six==1.16.0 --- uv sync --no-dev --locked six==1.16.0
The second sync removed humanize from .venv and kept six. uv.lock still contains both, so the same lockfile serves development and production.
Group selection
| Option | Installs |
|---|---|
| (none) | Project dependencies plus the dev group |
| --no-dev | Project dependencies only |
| --only-dev | Only the dev group, not the project dependencies |
| --group lint | Additionally the lint group |
| --no-group dev | Same as --no-dev |
| --only-group docs | Only the docs group |
| --all-groups | Every dependency group |
| --no-install-project | Dependencies without the project itself (Docker layer caching) |
Dockerfile
FROM python:3.13-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --locked --no-dev --no-install-project
COPY . .
RUN uv sync --locked --no-dev
CMD ["uv", "run", "--no-sync", "python", "-m", "app"]The first sync installs only third-party dependencies, so the layer is cached until the lockfile changes. --no-sync stops uv run from re-checking the environment at start-up.
Pitfalls
--lockedis the check thatuv.lockmatchespyproject.toml; without it a stale lock is silently updated during the build. The error it raises is explained in The lockfile needs to be updated.- A package the app imports at runtime but declared with
uv add --devworks locally and fails in production withModuleNotFoundError. Move it withuv add pkganduv remove --dev pkg. - Old projects that list dev tools under
[tool.uv] dev-dependenciesare treated as the dev group as well; the newer[dependency-groups]table (PEP 735) is preferred. uv runwithout--no-devre-syncs the dev group back into.venv; in production containers use--no-devor--no-syncon everyuv run.
FAQ
Does uv sync --no-dev remove dev packages that are already installed?
Yes. uv sync is exact by default: packages that are not part of the requested set are removed from .venv. Add --inexact to keep extra packages.
How do I skip dev dependencies for every uv sync?
Set default-groups = [] under [tool.uv] in pyproject.toml, so no group is installed unless requested with --group, or keep --no-dev in the Dockerfile and deploy scripts.
What about other dependency groups such as lint or docs?
Only the dev group is synced by default. Other groups are installed with --group NAME or --all-groups, and --only-group NAME installs a single group without the project's main dependencies.