π¦ Python Build Toolsο
Python has several tools for managing dependencies and virtual environments. This page covers two of the most popular modern options: Poetry and uv.
Poetryο
Poetry is a dependency management and packaging tool for Python. It handles virtual environments, dependency resolution, and publishing packages to PyPI β all from a single tool.
Configuration is stored in pyproject.toml, and a poetry.lock file pins exact dependency
versions for reproducible installs.
Common Commandsο
poetry installβ installs all dependencies frompyproject.tomlinto the venv (creates the venv if it doesnβt exist yet).poetry add <package>/poetry remove <package>β adds or removes a package. Both operations update the venv,pyproject.toml, andpoetry.locktogether.poetry add --group dev <package>β adds to a named dependency group (e.g.dev) instead of the main dependencies.poetry run <command>β runs a command inside the venv. Works for arbitrary commands (e.g.poetry run python main.py), for scripts installed by packages (e.g.poetry run pytest), or for scripts defined in your own project via[tool.poetry.scripts]inpyproject.toml(e.g.poetry run my-script). You can also launch VS Code viapoetry run code ., which gives VS Code access to the venv β enabling Go to Definition on installed packages.
pyproject.tomlο
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "A short description"
authors = ["Your Name <you@example.com>"]
[tool.poetry.scripts]
my-script = "my_package.module:main"
[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31"
my-lib = {path = "../my-lib"}
my-lib-dev = {path = "../my-lib", develop = true}
[tool.poetry.group.dev.dependencies]
pytest = "^8.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]: Project metadata β name, version, description, authors. Thenamefield is the distribution name (used for publishing), not related topoetry run.[tool.poetry.scripts]: Defines entrypoints for the project. The key is the script name and the value points to a Python callable (module:function). The key is what you pass topoetry run(e.g.my-script = ...is run withpoetry run my-script).[tool.poetry.dependencies]: Runtime dependencies. Thepythonkey sets the required interpreter version. Version constraints use^(compatible release, e.g.^3.11means>=3.11, <4.0). Local packages can be referenced by path; addingdevelop = truemakes it an editable install so changes to the local package are reflected immediately without reinstalling.[tool.poetry.group.<name>.dependencies]: Dependency groups for non-runtime packages. Group names are arbitrary βdev,test,lintetc. are all conventions. There are no built-in special group names. Exclude a group at install time withpoetry install --without dev.[build-system]: Tells build frontends how to build the package. Always points topoetry-corefor Poetry projects.
uvο
uv is an extremely fast Python package and project manager written in Rust, developed by Astral
(the team behind ruff). It can act as a drop-in replacement for pip, pip-tools, and
virtualenv, and also supports full project management similar to Poetry.
Common Commandsο
uv syncβ installs all dependencies into the venv (creates.venvif needed). This is the equivalent ofpoetry install.uv init my-projectβ scaffolds a new project with apyproject.toml. Not needed if you already have one.uv add <package>/uv remove <package>β adds or removes a dependency, updatingpyproject.tomlanduv.lock.uv add --dev <package>β adds to thedevdependency group ([dependency-groups]), keeping it separate from runtime dependencies.uv run <command>β runs a command inside the venv. Works for scripts and arbitrary commands, includinguv run code .to launch VS Code with Go to Definition support (same as Poetry).
Managing Python Versionsο
uv can manage Python interpreter installations without a separate tool like pyenv:
uv python install 3.12β downloads and installs a specific Python version, managed byuv.uv python pin 3.12β writes a.python-versionfile to the project directory. Alluvcommands run there will use that interpreter, downloading it automatically if not already installed.
pyproject.tomlο
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"requests>=2.31",
"my-lib",
]
[project.scripts]
my-script = "my_package.module:main"
[dependency-groups]
dev = [
"pytest>=8.0",
]
[tool.uv.sources]
my-lib = { path = "../my-lib", editable = true }
[project]: Standard PEP 621 metadata table. Used byuvand any other PEP 517-compliant tool.requires-pythonsets the minimum interpreter version.[project.dependencies]: Runtime dependencies declared as a list of PEP 508 strings (e.g."requests>=2.31"). Local packages are listed by name here, with their source declared separately in[tool.uv.sources].[project.scripts]: Defines entrypoints for the project. The key is the script name and the value points to a Python callable (module:function). The key is what you pass touv run(e.g.my-script = ...is run withuv run my-script). This is a standard PEP 621 field, so the scripts are also installed when the package is installed viapip.[tool.uv.sources]: Specifies where uv should fetch a dependency from. Settingeditable = truemakes changes to the local package reflect immediately without reinstalling. Any build backend is supported, including Poetry projects.[dependency-groups]: Optional groups for non-runtime dependencies (PEP 735). Equivalent to Poetryβs groups β install withuv sync --group devor exclude withuv sync --no-group dev.[build-system]: Only needed if you are building a distributable package.uvdefaults tohatchlingbut any PEP 517 backend works.
Note
Because uv uses the standard [project] table, the same pyproject.toml works with other
tools like pip install ., build, or hatch without any changes β you are not locked in
to uv to build or install the project.
Comparisonο
Both tools cover the same core workflow: dependency management, virtual environments, and packaging. The main differences are:
Speed:
uvis significantly faster at resolving and installing packages due to being written in Rust.Python management:
uvcan install and pin Python versions itself; Poetry relies on an external tool likepyenv.pip compatibility:
uvcan act as a drop-in replacement forpipviauv pip, making it easy to adopt incrementally.Config format:
uvuses the standard PEP 621[project]table; Poetry uses its own[tool.poetry]table.Maturity: Poetry has a larger established ecosystem;
uvis newer but rapidly adopted.
Both are solid choices. uv has the edge for new projects due to speed and built-in Python management.
Poetry remains a good choice if you are already familiar with it or need its publishing workflow.