poetry β Dependency Management & Packaging#
What it is#
Poetry manages Python project dependencies through pyproject.toml, creates and manages virtual environments automatically, and provides a workflow for building and publishing packages to PyPI. It replaced setup.py/requirements.txt/virtualenv combinations for many teams.
[!NOTE] uv offers a faster alternative for most poetry workflows in 2026. Poetry is still widely used and is the right choice if youβre already on it or your team prefers its DX.
Install#
# Official installer (recommended β does not pollute your project venv)
curl -sSL https://install.python-poetry.org | python3 -
# Or via pip (simpler, may cause version conflicts)
pip install poetry
Quick example β new project#
poetry new mylib
cd mylib
poetry add requests
poetry run python -c "import requests; print(requests.__version__)"
Output:
Created package mylib at mylib/
Using version ^2.32.3 for requests
Updating dependencies
Resolving dependencies... (0.3s)
Writing lock file
Package operations: 4 installs, 0 updates, 0 removals
β’ Installing certifi (2024.2.2)
β’ Installing charset-normalizer (3.3.2)
β’ Installing idna (3.7)
β’ Installing requests (2.32.3)
2.32.3
When / why to use it#
- You want a single tool for environment management, dependency resolution, and publishing.
- Your project needs strict lockfiles (for reproducible CI builds).
- Youβre publishing a library to PyPI β
poetry buildandpoetry publishmake this simple.
Common pitfalls#
[!WARNING]
poetry addchangespyproject.tomlandpoetry.lockβ always commit both files. The lockfile ensures every developer and CI run gets the exact same package versions.
[!WARNING] Poetry creates its own venv β it does not use the
.venvyou created withpython -m venv. Usepoetry env infoto find where Poetry put the venv, or configurepoetry config virtualenvs.in-project trueto place it in.venvat your project root.
[!TIP]
poetry shellactivates the managed venv in a new subshell. Exit withexit. Alternatively, prefix every command withpoetry runto avoid activating.
Richer example β full project workflow#
# Start a new project
poetry new my-api
cd my-api
# Add runtime and dev dependencies
poetry add "fastapi>=0.111" "uvicorn[standard]"
poetry add --group dev "pytest>=8" ruff mypy
# Install all deps (including dev) into the venv
poetry install
# Run tests
poetry run pytest
# Build sdist + wheel
poetry build
Output:
Package operations: 16 installs, 0 updates, 0 removals
β’ Installing anyio (4.4.0)
β’ Installing fastapi (0.111.1)
β’ Installing uvicorn (0.30.1)
...
============================= test session starts ==============================
collected 0 items
============================== no tests ran in 0.05s ==============================
Building my-api (0.1.0)
- Building sdist
- Built my-api-0.1.0.tar.gz
- Building wheel
- Built my_api-0.1.0-py3-none-any.whl
pyproject.toml structure#
[tool.poetry]
name = "my-api"
version = "0.1.0"
description = "A sample API"
authors = ["Jay Aharan <jay@example.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
fastapi = ">=0.111"
uvicorn = {extras = ["standard"], version = ">=0.30"}
[tool.poetry.group.dev.dependencies]
pytest = ">=8"
ruff = "*"
mypy = "*"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Essential commands#
| Command | Purpose |
|---|---|
poetry new <name> | Scaffold a new project |
poetry init | Interactively create pyproject.toml in existing directory |
poetry add <pkg> | Add a dependency |
poetry add --group dev <pkg> | Add a dev dependency |
poetry remove <pkg> | Remove a dependency |
poetry install | Install all deps from lockfile |
poetry install --only main | Install only runtime deps (for prod Docker) |
poetry update | Upgrade all deps within constraints |
poetry show | List installed packages |
poetry run <cmd> | Run command in the venv |
poetry shell | Spawn a shell with venv activated |
poetry build | Build sdist and wheel |
poetry publish | Publish to PyPI (requires API token) |
poetry env info | Show venv location and Python version |
poetry config virtualenvs.in-project true | Place venv in .venv/ |