|$ curl https://forge-ai.dev/api/markdown?path=docs/python/poetry-uv
$cat docs/poetry-&-uv.md
updated Today·18-24 min read·published

Poetry & uv

PythonPackaginguvIntermediate🎯Free Tools
Introduction

Modern Python packaging centers on pyproject.toml. pip + venv still works; Poetry pioneered lockfiles UX; uv is the ultra-fast installer/resolver from Astral.

pip vs Poetry vs uv
ToolStrengthLockfile
pip + venvUniversal, simplerequirements.txt (manual)
pip-toolsCompile pinsrequirements.txt
PoetryProjects + publish UXpoetry.lock
uvSpeed + pip/venv/poetry compatuv.lock
PDM / HatchPEP 621 focusvaries
pyproject.toml
pyproject.toml
TOML
1[project]
2name = "forge-demo"
3version = "0.1.0"
4description = "Demo"
5readme = "README.md"
6requires-python = ">=3.11"
7dependencies = [
8 "httpx>=0.27",
9 "pydantic>=2",
10]
11
12[project.optional-dependencies]
13dev = ["pytest>=8", "ruff>=0.6", "mypy>=1.11"]
14
15[project.scripts]
16forge-demo = "forge_demo.cli:main"
17
18[build-system]
19requires = ["hatchling"]
20build-backend = "hatchling.build"
uv Workflows
uv.sh
Bash
1# install uv: curl -LsSf https://astral.sh/uv/install.sh | sh
2uv init forge-demo && cd forge-demo
3uv add httpx pydantic
4uv add --dev pytest ruff mypy
5uv sync
6uv run pytest
7uv lock
8uv pip install -r requirements.txt # pip-compatible interface
9uv venv && source .venv/bin/activate
🔥

pro tip

uv sync creates .venv and installs from uv.lock — fast CI-friendly reproducible installs.
Poetry Workflows
poetry.sh
Bash
1poetry new forge-demo && cd forge-demo
2poetry add httpx pydantic
3poetry add --group dev pytest ruff mypy
4poetry install
5poetry run pytest
6poetry build
7poetry publish # needs credentials
poetry-pyproject.toml
TOML
1[tool.poetry]
2name = "forge-demo"
3version = "0.1.0"
4description = ""
5authors = ["You <you@example.com>"]
6packages = [{include = "forge_demo"}]
7
8[tool.poetry.dependencies]
9python = "^3.11"
10httpx = "^0.27"
11
12[tool.poetry.group.dev.dependencies]
13pytest = "^8.0"
14
15[build-system]
16requires = ["poetry-core"]
17build-backend = "poetry.core.masonry.api"
Lockfiles

Commit lockfiles for applications. Libraries may omit them or provide constraints — but apps should pin the world.

FileTool
poetry.lockPoetry
uv.lockuv
requirements.txtpip / pip-tools / uv pip compile
Pipfile.lockPipenv (legacy-ish)
Workspaces / Monorepos
uv-workspace.toml
TOML
1# uv workspaces (excerpt)
2[tool.uv.workspace]
3members = ["packages/*"]
4
5# Poetry: use plugins / multiple projects; or path deps:
6# mylib = { path = "../mylib", develop = true }
path-deps.sh
Bash
1# uv
2uv add --editable ../mylib
3# poetry
4poetry add --editable ../mylib
Still Using pip
pip.sh
Bash
1python -m venv .venv
2source .venv/bin/activate
3python -m pip install -U pip
4pip install -e ".[dev]"
5pip freeze > requirements.txt # crude; prefer uv pip compile / pip-tools

warning

pip freeze captures transitive pins but loses the distinction between direct and transitive deps. Prefer lock tools.
CI Pattern
ci.sh
Bash
1uv sync --frozen
2uv run ruff check .
3uv run mypy src
4uv run pytest -q
Version Specifiers
versions.toml
TOML
1# PEP 440 examples in dependencies:
2# "httpx>=0.27,<0.29"
3# "pydantic~=2.8" # compatible release
4# "django>=5.0.0"
SpecifierMeaning
>=1.2.3Lower bound
~=1.2.3>=1.2.3,<1.3.0 compatible
==1.2.3Exact pin (apps via lock)
^1.2 (Poetry)Semver caret
Exporting Requirements
export.sh
Bash
1# poetry
2poetry export -f requirements.txt --output requirements.txt --without-hashes
3# uv
4uv export --no-hashes -o requirements.txt
5# useful for platforms that only accept requirements.txt
Align with Ruff / Pytest
tools.toml
TOML
1[tool.ruff]
2line-length = 88
3target-version = "py311"
4
5[tool.pytest.ini_options]
6testpaths = ["tests"]
7
8[tool.mypy]
9python_version = "3.11"
10strict = true
Which Should You Pick?
  • Greenfield apps in 2026: uv is an excellent default
  • Existing Poetry repos: stay on Poetry or migrate carefully to uv
  • Library maintainers: PEP 621 pyproject + tox/nox; lock optional
  • Simple scripts: uvx / pipx for tools; uv run for project scripts
Migrating Poetry → uv
migrate.sh
Bash
1# Rough path:
2# 1. Ensure pyproject has [project] deps (Poetry 2 / export)
3# 2. uv lock
4# 3. uv sync
5# 4. Replace poetry run with uv run in CI
6# 5. Keep poetry.lock until uv.lock verified
  • Translate ^ constraints carefully
  • Re-run tests under uv sync --frozen
  • Update Dockerfile to astral-sh/uv image or install script
Docker Snippet
Dockerfile
Dockerfile
1# FROM python:3.12-slim
2# COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
3# WORKDIR /app
4# COPY pyproject.toml uv.lock ./
5# RUN uv sync --frozen --no-dev
6# COPY . .
7# CMD ["uv", "run", "uvicorn", "app:app", "--host", "0.0.0.0"]
Scripts & Entrypoints
scripts.toml
TOML
1[project.scripts]
2forge = "forge_demo.cli:main"
3
4# then: uv run forge --help
5# or after sync: .venv/bin/forge
$Blueprint — Engineering Documentation·Section ID: PYTHON-POETRY-UV·Revision: 1.0

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.