Dependency Management (poetry, pipenv)
Installing packages with pip and tracking them in a requirements.txt file is the simplest way to manage dependencies in Python, but it starts to show cracks as a project grows. Tools like Poetry and Pipenv exist to close those gaps with proper dependency resolution, lock files, and a single source of truth for a project's metadata.
The limits of pip + requirements.txt
No real lock file —
requirements.txttypically lists only the packages you asked for. Unless you runpip freezeand pin every transitive dependency by hand, the exact versions of your dependencies' dependencies aren't recorded anywhere, so two installs months apart can pull in different sub-dependency versions.Weak resolution guarantees — pip's resolver checks that the packages you ask for are compatible at install time, but it doesn't produce a single deterministic solution the way a true dependency resolver does. The same requirements file can end up resolving slightly differently on different machines or at different times as new package versions are published.
No dev/prod separation — pip has no built-in concept of "development-only" dependencies (linters, test runners). Projects work around this with multiple files (
requirements.txt,requirements-dev.txt) that have to be maintained and installed separately, and it's easy for them to drift out of sync.
Poetry and Pipenv both address these problems by combining dependency declaration, resolution, and locking into one workflow.
Poetry
Poetry manages a project's dependencies, metadata, and (optionally) packaging/publishing entirely through a single pyproject.toml file — no separate setup.py or requirements files needed.
# pyproject.toml [tool.poetry] name = "my-project" version = "0.1.0" description = "An example project managed with Poetry" authors = ["Jane Doe <jane@example.com>"] [tool.poetry.dependencies] python = "^3.11" requests = "^2.31.0" [tool.poetry.group.dev.dependencies] pytest = "^8.0.0" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api"
Adding a new dependency updates pyproject.toml and installs it into an automatically managed virtual environment in one step:
poetry add requests
To install everything an existing project declares — for example after cloning a repository — run:
poetry install
Both commands write and read poetry.lock, a file that pins the exact version of every dependency and every transitive dependency, along with hashes for verification. Committing poetry.lock guarantees that everyone on the team, and every deployment, installs byte-for-byte the same dependency tree.
For new projects, Poetry is a solid default: one config file, automatic virtual environment management, a real lock file, and built-in support for publishing to PyPI with poetry publish when you're ready to release a package.
Pipenv
Pipenv takes a different angle: rather than replacing pip and venv, it wraps both into a single command-line tool. Dependencies are declared in a Pipfile (a friendlier alternative to requirements.txt), and Pipenv generates a Pipfile.lock for reproducible installs, the same way Poetry generates poetry.lock.
# Add a dependency (creates a venv automatically if one doesn't exist) pipenv install requests # Activate the managed virtual environment pipenv shell
Pipenv separates default and development dependencies natively (pipenv install --dev pytest), which solves the dev/prod split that plain requirements.txt struggles with, but — unlike Poetry — it has no built-in support for building or publishing packages to PyPI.
Comparing the options
Tool | Lock File | Virtual Env Management | Publishing Support |
|---|---|---|---|
pip + venv | No lock file by default (manual | Manual ( | None built-in |
Poetry |
| Automatic | Built-in ( |
Pipenv |
| Automatic | None built-in |
All three approaches ultimately install packages from PyPI (the Python Package Index) — Poetry and Pipenv don't introduce a different package source, they just add resolution, locking, and workflow conveniences on top of the same underlying package ecosystem pip uses.
Plain
pip+requirements.txthas no real lock file, weak resolution guarantees, and no native dev/prod dependency split.Poetry centers on
pyproject.toml+poetry.lock, manages its own virtual environment, and can publish packages directly to PyPI.Pipenv centers on
Pipfile+Pipfile.lock, also manages its own virtual environment, but has no built-in publishing support.For new projects, Poetry is generally the recommended starting point.