uv is an open source Python package and project manager from Astral. It combines dependency installation, virtual environments, and Python version management in one Rust-based tool, so teams can manage a project without assembling a separate tool for each job.
Vercel uses uv for Python builds and reported 30 to 65% faster builds after adopting it. Results vary with the dependencies and cache available to each build.
Key takeaways:
uv is a Python package and project manager from Astral that replaces pip, pip-tools, pyenv, and virtualenv with one tool.
Its Rust implementation combines conflict-aware resolution, selective metadata downloads, and a shared package cache to reduce installation work.
The biggest speedups need a warm cache, so they depend on keeping that cache between builds.
uv installs Python packages from the Python Package Index (PyPI) and other indexes, including wheels with native code. System libraries that those packages do not bundle need separate installation.
uv's lockfile,
uv.lock, is uv-specific, anduv exportconverts it when another tool needs a standard format.
Copy link to headingWhat is uv and what does it replace?
uv is an open source tool for managing Python projects, written in Rust by Astral, the company behind the Ruff linter. It launched in 2024 as a drop-in replacement for pip and pip-tools, then grew into a full project manager with its own lockfile later that year.
The uv pip interface lets a project switch installers before adopting uv's project commands. Check its pip compatibility differences, especially configuration files and package-index selection, before replacing an existing install step.
Copy link to headingHow uv's commands map to existing tools
Each job in a conventional Python toolchain maps onto a uv command:
In a uv workspace, each member has its own pyproject.toml and all members share one uv.lock. Dependencies resolve together, which suits related packages that can use compatible versions.
Copy link to headingWhy Python teams are switching to uv
Speed is the headline, though it isn't the only reason developers switch. Three properties do most of the work:
Astral reports 10 to 100 times faster package operations than pip. The gain depends on the workload and cache state.
The universal
uv.lockrecords dependencies across supported Python versions and platforms. Environment markers select the applicable packages during installation, allowing macOS development and Linux builds to share a lockfile.uv python installdownloads supported Python interpreters as part of the same project toolchain.
Of the three, speed varies most from project to project, because it depends on which of uv's design decisions a given install gets to use.
Copy link to headingDesign decisions behind the uv package manager's speed
Dependency installation can involve resolution, metadata retrieval, downloads, and unpacking or building packages. Existing lockfiles and cached artifacts let uv skip some of that work. Its implementation also reduces the cost of the work that remains.
Copy link to heading1. Native startup
uv starts as a compiled Rust binary. Python-based installers first load an interpreter and their own modules, so native startup can help with short, repeated commands. Source builds may still invoke a Python build backend, and their cost can outweigh the installer's startup time.
Copy link to heading2. PubGrub dependency resolution
uv uses the Rust implementation of PubGrub to select compatible package versions. When it encounters a conflict, it records the incompatible choices and backtracks with that information, avoiding the same failed combination later.
Those recorded conflicts also help explain why a resolution failed. Within uv's resolution process, loading package metadata is usually the slowest part, even when the metadata is cached.
Copy link to heading3. Package metadata without full downloads
For a wheel, the packaged ZIP archive contains metadata describing its dependencies. uv can read that metadata during resolution without downloading the entire wheel. It tries progressively larger requests:
Request the
METADATAfile directly from the index, using the static metadata endpoint defined by Python Enhancement Proposal (PEP) 658.Failing that, issue an HTTP range request for the zip central directory at the end of the wheel, read the offset of the metadata file, and fetch that byte range.
Only if both fail, download the full wheel.
Metadata-only requests save more bandwidth for large wheels. uv still needs the selected artifact for installation unless it is already cached, but it can reject unsuitable candidates without downloading their full contents.
Copy link to heading4. Parallel downloads into a shared global cache
uv allows up to 50 concurrent downloads by default and stores reusable artifacts in a shared cache.
When installing cached wheels, uv defaults to copy-on-write clones on macOS and Linux and hardlinks on Windows. These methods reduce duplicate data where the filesystem supports them; copying remains necessary when linking is unavailable.
In Astral's 2024 launch benchmarks, uv resolved and installed Trio's dependencies 8 to 10 times faster than pip and pip-tools without a cache and 80 to 115 times faster with a warm cache.
Warm-cache installs reuse artifacts from earlier runs. Fresh containers and continuous integration (CI) jobs that do not restore a cache must fetch them again, so measure your own workflow with the cache conditions it will use in production.
Copy link to headingWhen to use uv instead of pip, Poetry, or conda
uv suits teams that want installation and project management in one tool. Existing CI conventions, lockfile requirements, and dependencies outside the Python packaging ecosystem can make other tools a better fit:
Both uv and Poetry use environment markers to support cross-platform dependencies. Neither lockfile guarantees that every target has a compatible binary or all the system libraries a package needs.
For example, uv can install CUDA-enabled PyTorch wheels. Conda can manage non-Python packages alongside Python dependencies. OS packages or a prepared container image can supply other required libraries.
Copy link to headingHow to adopt uv in a Python project
In a uv project, commit pyproject.toml for dependency declarations and uv.lock for resolved versions. For a pip-tools workflow, compile declarations from requirements.in into a pinned requirements.txt.
Copy link to headingStart a new project with uv init
uv init --no-package creates pyproject.toml, .python-version, README.md, and a starter main.py. Select Python 3.12 during initialization so the version pin and project's minimum Python version agree:
uv init --no-package --python 3.12 my-servicecd my-serviceuv add fastapiuv add --dev pytestuv run pytest --versionThe first dependency operation creates .venv/ and uv.lock. uv run uses that project environment without a separate activation step. Once you have added tests, run them with uv run pytest and commit the lockfile alongside pyproject.toml.
Copy link to headingMigrate a requirements.txt project without moving pins
For a pip-tools project, requirements.in contains direct dependency declarations and requirements.txt contains the tested pins. After initializing the uv project, run uv add -r requirements.in -c requirements.txt to retain those versions as constraints. Compare the generated lockfile before committing the migration.
Projects with separate pins for multiple platforms need the platform-specific migration steps to preserve their environment markers.
To keep the requirements-file workflow, run these commands for the same target environment as the existing pins:
uv venvuv pip compile requirements.in -c requirements.txt --output-file requirements.txtuv pip sync requirements.txtThe pip interface retains your requirements files while using uv's resolver and cache. Teams can keep this workflow if they do not need uv's project commands.
Copy link to headingMigrate a Poetry project with migrate-to-uv
The community-maintained migrate-to-uv tool converts Poetry metadata and dependency groups into uv-compatible project settings. Running uvx migrate-to-uv also generates a uv.lock using the versions in an existing poetry.lock.
For everyday installs, uv sync removes packages outside the selected dependency set. uv sync --inexact retains extra installed packages, matching that aspect of poetry install. The following commands cover common operations:
Review the converted version constraints and dependency sources, then run the project's tests in the new environment. The migration also translates Poetry's caret syntax into standard version specifiers.
Copy link to headingFail CI builds when uv.lock drifts
Use uv sync --locked in CI to fail when pyproject.toml and uv.lock disagree. --frozen uses the existing lock without checking the project declarations, so reserve it for workflows that validate the lockfile separately.
If CI uses GitHub Actions, pin both uv and the setup action. Since setup-uv v8.0.0, releases use immutable full-version tags instead of moving major or minor tags. Use a full release tag or commit SHA; astral-sh/setup-uv@v8 does not resolve.
Copy link to headingCache the dependency layer in Docker
Install dependencies in a separate Docker layer before copying frequently changing application code. uv's Docker example first uses uv sync --frozen --no-install-project with the lockfile available, then copies the project and runs uv sync --locked to validate and install it.
Set UV_LINK_MODE=copy when the BuildKit cache mount and target environment use different filesystems to copy files without link-fallback warnings.
Copy link to headingHow Vercel runs uv for Python teams
Vercel provides the Python installer and build-cache handling. Your repository still defines the dependencies and supported Python version that those builds use.
Copy link to headinguv as the default installer on every Python build
Vercel uses uv by default for Python builds, so adopting it locally does not require a custom installer command on Vercel.
The Python runtime accepts pyproject.toml with or without uv.lock, a requirements.txt, or a Pipfile paired with Pipfile.lock. Commit the resolved dependency file used by your deployment workflow.
Copy link to headingReusing the build cache
Vercel restores an available build cache before installation. Reusable dependencies can then avoid a fresh download, although cache misses and changed dependencies still require work.
Cache reuse does not predict a fixed speedup. Compare build times for your own dependency set with and without cache reuse, and inspect the build logs when installation unexpectedly slows down.
Copy link to headingPython versions pinned with .python-version
uv.lock can cover multiple Python versions, but deployments still need an interpreter compatible with the project's requires-python range and its dependencies.
Vercel supports Python 3.12, 3.13, and 3.14, with 3.12 as the default when no supported version is declared. Use uv python pin 3.12 to write that version to .python-version, and keep it compatible with requires-python in pyproject.toml. Vercel also accepts version information from Pipfile.lock.
Copy link to headingBundle limits sized for large dependency trees
Machine learning packages and native extensions can push a Python dependency set past a conventional function bundle long before application code adds much. Teams then end up splitting functions or stripping dependencies to fit.
Python Functions have a standard uncompressed bundle limit of 500 MB. The Large Functions beta supports up to 5 GB with Fluid compute and Active CPU enabled. Secure Compute and Static IPs are not supported during the beta.
Python bundles have no automatic tree-shaking. Use excludeFiles under the function's configuration in vercel.json to remove unnecessary tests, fixtures, and other files, and keep runtime dependencies limited to what the application uses.
Copy link to headinguv preinstalled in Vercel Sandbox
Vercel Sandbox's default managed universal image includes Python 3.14 and uv for installing dependencies within a session.
The image's rolling latest tag receives updates. Pin an image digest when the execution environment needs to remain reproducible.
Copy link to headingShip faster Python builds on Vercel
Start with one project's tested dependency set. Preserve its versions during migration, run the tests with uv, and compare installation time under the cache conditions used by CI.
Import the repository into Vercel or browse Python framework starters to deploy it.
Copy link to headingFrequently asked questions about the uv Python package manager
Copy link to headingIs uv stable enough for production use?
Yes. uv is used in production, and its versioning policy places breaking changes in minor releases. Pin the uv version used by CI, review release notes, and test upgrades before changing that pin.
Copy link to headingShould a project keep both uv.lock and requirements.txt?
Keep both when another installer needs requirements.txt, but generate that file from uv.lock with uv export. Commit the export if the deployment workflow requires it, and regenerate it whenever the lockfile changes. Avoid maintaining two independent sets of pins.
Copy link to headingHow does uv interact with Vercel's build cache?
Each successful build updates the cache for the next one, and a failed build leaves it untouched, so one broken deploy doesn't degrade later installs. To rule the cache out while debugging, redeploy without the existing build cache or set VERCEL_FORCE_NO_BUILD_CACHE to 1.