Python packaging shifts as uv gains dominance
The Rust-based tool uv performs package installations 10 to 100 times faster than pip while consolidating tools like pip, pyenv, and pip-tools. It streamlines workflows through PEP 723 inline script metadata and provides a seamless migration path from Poetry via specialized conversion tools.
uv performs package installations 10 to 100 times faster than pip. This Rust-based tool replaces pip, virtualenv, pyenv, and pip-tools with a single binary. While PDM maintains compliance with PEP 582, uv consolidates the stack by managing Python versions and environments. Poetry remains a choice for library publishing, but its 1.6 to 2.0 versions broke compatibility in pyproject.toml. Some developers reported that Poetry flips random write bits on installed packets during builds. These issues drive users toward more reliable alternatives. I prefer the speed of the Rust implementation. The tool also replaces pipx by providing the uvx command. This command runs tools like Ruff, Mypy, or Black in isolated environments without permanent installs. While pip handles basic installation, uv offers a unified approach that addresses the needs of both casual users and power users. Casual users appreciate the ability to run tools once without housekeeping, while power users value the speed of dependency resolution. This performance boost comes from the Rust-based architecture, which optimizes resource usage during package installation and dependency resolution. For data science workloads, Conda remains a common choice, but uv targets a broader range of development needs.
PEP 723 enables inline script metadata for standalone Python files. This format allows developers to define dependencies directly in the script. uv uses this metadata to create isolated environments during a uv run command. A user can add a dependency like httpx using uv add –script. This command adds a script section at the top of the script declaring the dependencies using TOML. To provide reproducible environments, uv lock –script creates a lockfile like example.py.lock. This lockfile contains pinned versions and hashes for every dependency. If a user provides a shebang, the script runs with uv without needing the uv run command. This works on Linux, macOS, and Windows. For macOS, the -S in the shebang is optional. uv also supports the exclude-newer field in the tool.uv section to limit distributions to those released before a specific date. Users specify this date using an RFC 3339 timestamp. You can also request dependencies per invocation with the –with option. This bypasses the need for a project directory. If a script has no dependencies, it runs with uv run script.py. If the script depends on a module in the standard library, nothing more is needed. You can also provide arguments to the script or read it directly from stdin. If you use uv run in a directory with a pyproject.toml, the tool installs the current project before running the script. Using the –no-project flag skips this step. uv also searches for and downloads the required Python version if it is not present. On Windows, uv runs a script with a .pyw extension using pythonw. You can use uv init –script to initialize scripts with the inline metadata.
Migrating from Poetry to uv works well for many projects. The migrate-to-uv tool converts Poetry version specifiers into the PEP 440 format and moves dependency groups to the new dependency-groups structure. It also converts git, path, or URL dependencies into the [tool.uv.sources] format. Developers switching from Poetry to uv report that the transition works without issues because the tool handles the conversion of dependency groups and version specifiers into the new PEP 621 and PEP 735 standards. In CI/CD pipelines, uv shrinks Docker image build times. While a pip install takes 30 to 90 seconds, uv finishes in 2 to 5 seconds with a warm cache. The 44MB uv binary replaces the enormous Python stack in many environments. A simple uv sync command replaces the need for separate environment creation commands. In monorepos, uv uses a single top-level lockfile at the workspace root instead of per-package lockfiles. The migration tool preserves exact versions from poetry.lock when generating uv.lock. The uv documentation for tool upgrade contains errors about –refresh and –refresh-package options that do not exist. I recommend uv for any developer who values speed and easy environment management. Does the community eventually move away from the fragmentation caused by so many different tools?