# pip-tools: Python Dependency Pinning Tools


pip-tools is a set of command-line utilities for managing Python dependency pinning. It consists of two commands: `pip-compile` for resolving and locking dependencies, and `pip-sync` for synchronizing a virtual environment to match a [lockfile](https://pydevtools.com/handbook/explanation/what-is-a-lock-file/index.md).

> [!NOTE]
> [uv](https://pydevtools.com/handbook/reference/uv/index.md) provides `uv pip compile` and `uv pip sync` as faster, drop-in replacements for pip-tools. For new projects, uv is the recommended approach. [pip](https://pydevtools.com/handbook/reference/pip/index.md) itself added an experimental `pip lock` command in 25.1 (April 2025) that writes [PEP 751](https://pydevtools.com/handbook/explanation/what-is-pep-751/index.md) `pylock.toml` files, but `pip lock` locks to the current Python version and platform only. pip-tools remains useful for cross-platform `requirements.txt` generation.

## pip-compile

`pip-compile` reads a set of direct dependencies and resolves them into a fully pinned [requirements.txt](https://pydevtools.com/handbook/reference/requirements/index.md) file, including all transitive dependencies. It accepts input from `requirements.in`, [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml/index.md), `setup.cfg`, or `setup.py`.

```bash
# From requirements.in
pip-compile requirements.in

# From pyproject.toml
pip-compile pyproject.toml

# Upgrade all packages
pip-compile --upgrade requirements.in

# Upgrade a specific package
pip-compile --upgrade-package requests requirements.in

# Generate hashes for verification
pip-compile --generate-hashes requirements.in
```

A typical `requirements.in` file lists direct dependencies with loose constraints:

```text
flask>=2.0
requests
```

Running `pip-compile requirements.in` produces a `requirements.txt` with pinned versions:

```text
# This file is autogenerated by pip-compile with Python 3.12
blinker==1.9.0
    # via flask
certifi==2024.8.30
    # via requests
charset-normalizer==3.4.0
    # via requests
click==8.1.7
    # via flask
flask==3.1.0
    # via -r requirements.in
idna==3.10
    # via requests
itsdangerous==2.2.0
    # via flask
jinja2==3.1.4
    # via flask
markupsafe==3.0.2
    # via jinja2
requests==2.32.3
    # via -r requirements.in
urllib3==2.2.3
    # via requests
werkzeug==3.1.3
    # via flask
```

Each entry shows the exact version and which package required it.

## pip-sync

`pip-sync` installs, upgrades, and removes packages so that the active virtual environment matches the lockfile exactly. Unlike `pip install -r`, which only adds and upgrades packages, `pip-sync` also removes packages that are not listed.

```bash
# Sync environment to a single lockfile
pip-sync requirements.txt

# Sync multiple lockfiles (e.g., production and development)
pip-sync requirements.txt dev-requirements.txt
```

## Typical Workflow

1. Maintain a `requirements.in` file with direct dependencies.
2. Run `pip-compile requirements.in` to resolve and pin all versions.
3. Run `pip-sync requirements.txt` inside a [virtual environment](https://pydevtools.com/handbook/reference/venv/index.md) to install the exact dependency set.
4. When adding or upgrading a dependency, edit `requirements.in` and re-run `pip-compile`.

For projects using [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml/index.md) as the dependency source, replace `requirements.in` with `pyproject.toml` in the commands above.

## Limitations

- Lockfiles are platform-specific. A lockfile generated on macOS may not resolve correctly on Linux.
- Resolution speed is slower than [uv](https://pydevtools.com/handbook/reference/uv/index.md).
- No virtual environment creation. A tool like [venv](https://pydevtools.com/handbook/reference/venv/index.md) or virtualenv is still needed.
- No Python version management.

## Learn More

- [pip-tools documentation](https://pip-tools.readthedocs.io/en/latest/)
- [pip-tools on GitHub](https://github.com/jazzband/pip-tools)
- [What is a lockfile?](https://pydevtools.com/handbook/explanation/what-is-a-lock-file/index.md)
