uv review
uv 0.12.6 is Astral's compiled command-line manager for Python dependencies, environments, lockfiles, interpreters, tools, scripts, builds, and package publishing. Project mode records dependencies in pyproject.toml, resolves a cross-platform uv.lock, and maintains a project .venv. The separate uv pip commands can compile and sync requirements without moving a repository to uv's project model. Version 0.12.6 updates managed CPython's OpenSSL and libffi, improves cache size accounting, adds profile-guided optimization to release binaries, and fixes several build, workspace, and credential-cache cases.
Our uv 0.12.5 install took 0.4 seconds, occupied 1 MB, and returned 0 audit findings; current 0.12.6 adds binary and cache work without changing that measured result. uv fits teams willing to make the lockfile authoritative, pin the CLI in CI, and govern its interpreter and index downloads.
We installed it
| Install | ✓ · 0.4s | 1 package on disk · 1 MB |
| Import | ✓ | import uv in 0.05s · compiled extensions · py.typed · requires Python >=3.8 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does uv install cleanly?
Yes. In a fresh container with an empty cache, pip install uv finished in 0.4s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does uv need to run?
Python >=3.8, and a platform wheel with compiled extensions. In our run import uv succeeded in 0.05s, and the package ships py.typed for type checkers.
uv or poetry: which should you use?
poetry: Choose it when an existing Poetry lock, plugin set, and publishing workflow already satisfy the team's needs. Our uv 0.12.5 install took 0.4 seconds, occupied 1 MB, and returned 0 audit findings; current 0.12.6 adds binary and cache work without changing that measured result.
When should you not use uv?
The environment depends on Conda channels for CUDA, system libraries, or other non-Python artifacts; uv resolves Python packages and does not replace Conda's environment solver
Discussed on
- hnuv: An extremely fast Python package and project manager, written in Rust753 points
- hnWarn about PyPy being unmaintained326 points
- hnuv: Deduplicate all files in the wheel cache231 points
- hnUv 0.12.0131 points
- hnYou can now uv run a GitHub gist33 points
Use it if
- A Python project needs one command for locking, environment sync, execution, interpreter selection, building, and publishing
- CI spends meaningful time resolving or installing requirements and can use uv's compiled binaries and shared cache
- Developers need pinned CPython or PyPy versions without compiling interpreters locally
- You want pipx-style command isolation through uvx or PEP 723 dependencies embedded in a single Python script
- The environment depends on Conda channels for CUDA, system libraries, or other non-Python artifacts; uv resolves Python packages and does not replace Conda's environment solver
- A Poetry, PDM, or Pipenv deployment relies on plugins, custom commands, or lock semantics that have not been matched in a migration test
- Operators plan to install packages manually into the project .venv; uv sync treats the declared lock as authority and can remove packages outside it
- Security policy forbids tools from downloading interpreters or contacting undeclared indexes; uv can fetch managed Python builds and needs those sources configured or disabled deliberately
- The target has no supported prebuilt binary and cannot use a compatible PyPI wheel or standalone archive; the ordinary install path depends on compiled platform artifacts
Setup reality
We installed uv 0.12.5 into Python 3.12 in 0.4 seconds. That measured install left 1 package and 1 MB on disk, declared 0 direct dependencies, and produced 0 pip-audit findings. The wheel requires Python 3.8 or newer, contains compiled .so files, and ships py.typed. import uv worked in 0.05 seconds, although the supported workflow is the uv executable. The current release is 0.12.6, which we did not rerun through that sandbox.
Pick one installation owner. The standalone binary can update itself, while pip, pipx, Homebrew, WinGet, and other package managers expect to control upgrades. uv may download a managed interpreter when no acceptable Python is present. In CI, decide whether that network action is allowed, pin the uv release, and either preinstall Python or point downloads at an approved mirror. Version 0.12.6 refreshes OpenSSL and libffi inside Astral's managed CPython builds.
Project sync treats pyproject.toml and uv.lock as the desired state for .venv. A manual pip install is disposable and may vanish on the next uv sync. Commit the lockfile, use --locked when CI should verify it is current, or use --frozen when CI must consume it without checking project metadata. The global cache shares artifacts across environments; container builds should mount it intentionally and prune it rather than assuming .venv contains every physical byte.
Private indexes need an explicit resolution policy because dependency confusion is possible when a name exists publicly and privately. Keep tokens out of committed URLs and use uv's supported environment variables, keyring integration, or CI secrets. A universal lock can describe forks for multiple Python versions and platforms, but installation still selects platform wheels or builds source distributions. Test every deployment target, especially packages with native code, and pin any preview feature that production depends on.
Patterns
Start a packaged application create-packaged-project
uv init example
cd example
uv add httpx
uv run exampleSince uv 0.12, uv init creates a packaged src layout with uv_build by default. Use uv init --no-package when the repository should remain an unpackaged application.
Record and lock a dependency add-runtime-dependency
uv add 'httpx>=0.28'
uv run python -c 'import httpx; print(httpx.__version__)'uv add edits pyproject.toml and refreshes uv.lock. Review both changes because the declared constraint and the resolved version serve different purposes.
Fail CI when the lock is stale verify-locked-sync
uv sync --locked
uv run pytest--locked checks that uv.lock agrees with project metadata and refuses to change it. --frozen skips that freshness check and consumes the existing lock as written.
Exclude development dependencies install-production-groups
uv add --dev pytest ruff
uv sync --no-devNormal project sync includes the default development group. Production images need an explicit group selection rather than assuming dev packages are absent.
Refresh one locked package upgrade-one-resolution
uv lock --upgrade-package httpx
uv syncThis updates the locked httpx resolution within the constraint already stored in pyproject.toml. Use uv add when the declared constraint itself must change.
Install and select Python 3.12 pin-managed-python
uv python install 3.12
uv python pin 3.12
uv run python --versionuv python pin writes .python-version. CI should state whether uv may download that interpreter or must find an approved preinstalled build.
Execute a packaged command with uvx run-isolated-tool
uvx --from 'ruff==0.13.0' ruff check .uvx runs the command from a cached isolated environment. Pin the package version when CI output must not change with the registry's latest release.
Give one script PEP 723 metadata declare-script-dependencies
uv init --script report.py --python 3.12
uv add --script report.py pandas
uv run report.pyuv writes dependency metadata into report.py and manages an isolated environment for it. The script remains the source of its dependency declarations.
Keep a requirements deployment compile-hashed-requirements
uv pip compile requirements.in \
--universal \
--generate-hashes \
--output-file requirements.txt
uv pip sync requirements.txtuv pip compile does not create uv.lock. Commit requirements.txt when that compiled file is the artifact consumed during deployment.
Bind one package to a private index name-private-index
[[tool.uv.index]]
name = "company"
url = "https://packages.example.com/simple"
explicit = true
[tool.uv.sources]
internal-lib = { index = "company" }explicit prevents unrelated packages from resolving through this index. Supply its credentials outside pyproject.toml through an approved secret mechanism.
Create wheel and source archives build-package-artifacts
uv build
python -m zipfile -l dist/example-0.1.0-py3-none-any.whluv build writes distribution files under dist by default. Inspect their contents and test the wheel before sending it to a registry.
Measure and prune the cache maintain-shared-cache
uv cache dir
uv cache size
uv cache prune --ciVersion 0.12.6 reports cache savings using filesystem block allocation and avoids double-counting hard links. Container jobs still need an explicit cache mount and retention policy.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| poetry | PyPI | Choose it when an existing Poetry lock, plugin set, and publishing workflow already satisfy the team's needs |
| pdm | PyPI | Choose it when the project is built around PDM plugins, PEP 582 history, or PDM-specific workspace behavior |
| pipenv | PyPI | Choose it when Pipfile and Pipfile.lock are an organizational standard that other tooling already consumes |
More cli & tooling guides
commander · chalk · typescript · esbuild · yargs · click · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

