Constraints & Build Constraints

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the Python Reference bibliography.

A requirement says "install this". A constraint says "if this gets installed, it must be this version". pip has two kinds: ordinary constraints for the packages it installs into your environment, and build constraints for the packages it installs into the temporary environments where sdists are built. This page was written against pip 26.2.2 and run on CPython 3.14.6 on 2026-10-22.

Constraints files (-c)

A constraints file uses the requirements-file syntax, given with -c <file> (on the command line or inside a requirements file), PIP_CONSTRAINT, or a URL so that an organisation can serve one central file. Listing a package in it never causes it to be installed; it only restricts the version chosen when something else requires it. The birdtally-report requirements file includes one:

# organisation-wide pins: only apply if something requires them
pygments == 2.21.0
markdown-it-py == 4.2.0

Typical uses:

  • Organisation-wide or monorepo pins. One constraints.txt keeps every project on the same versions of shared dependencies without making every project depend on all of them.

  • Security pins. Forbid a vulnerable range (urllib3 >= 2.6.3) everywhere a dependency might pull it in.

  • Avoiding a broken release of an indirect dependency until upstream fixes it.

A constraint that conflicts with a requirement is a resolution error that names the constraint:

printf 'pygments==2.19.0\n' > c2.txt
python -m pip install --dry-run --ignore-installed -c c2.txt "pygments>=2.20"
ERROR: Cannot install pygments>=2.20 because these package versions have conflicting dependencies.

The conflict is caused by:
    The user requested pygments>=2.20
    The user requested (constraint) pygments==2.19.0

Additionally, some packages in these conflicts have no matching distributions available for your environment:
    pygments

To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip to attempt to solve the dependency conflict

ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts

What a constraint may contain

Constraints exist since pip 7.1. When the new resolver arrived in 20.3, they were "stripped down to being purely a way to specify global (version) limits": a constraint must have a name, it cannot be editable and it cannot have extras.

printf 'rich[jupyter]==15.0.0\n' > bad-constraints.txt
python -m pip install --dry-run -c bad-constraints.txt rich
DEPRECATION: Constraints are only allowed to take the form of a package name and a version specifier. Other forms were originally permitted as an accident of the implementation, but were undocumented. The new implementation of the resolver no longer supports these forms. A possible replacement is replacing the constraint with a requirement. Discussion can be found at https://github.com/pypa/pip/issues/8210
ERROR: Constraints cannot have extras

Hashes in constraints (26.1)

Since pip 26.1 a --hash on a constraint line applies to the constrained package, so a constraints file can carry the hashes of an organisation’s approved files. With a deliberately wrong hash:

printf 'tomli-w==1.2.0 --hash=sha256:0000000000000000000000000000000000000000000000000000000000000000\n' > hc.txt
python -m pip install --dry-run --ignore-installed -c hc.txt tomli-w
Collecting tomli-w==1.2.0
  Using cached tomli_w-1.2.0-py3-none-any.whl (6.7 kB)
ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them.
    tomli-w==1.2.0 from https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl:
        Expected sha256 0000000000000000000000000000000000000000000000000000000000000000
             Got        188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90

Hash-checking mode itself is on Repeatable & Secure Installs.

Constraints or a lock file?

The dependency-resolution guide recommends constraints files (or lock files) to cut down backtracking: they tell the resolver the answer in advance. A lock file pins everything one environment needs; a constraints file pins some things for any environment. poetry export -f constraints.txt turns a Poetry lock into a constraints file.

Build constraints (--build-constraint, pip 25.3)

When pip builds a package from an sdist or a local directory, it installs the [build-system] requires into a fresh, isolated environment (see Build System Interface). Those build dependencies are resolved separately, and usually to the newest versions. A build constraints file restricts them, and only them: --build-constraint <file> or PIP_BUILD_CONSTRAINT.

printf 'hatchling==1.27.0\n' > build-constraints.txt
python -m pip wheel --no-deps --no-cache-dir -w wh --build-constraint build-constraints.txt ./birdtally -v
unzip -p wh/*.whl '*/WHEEL' | grep Generator
…
    Obtaining dependency information for hatchling>=1.27 from https://files.pythonhosted.org/packages/08/e7/ae38d7a6dfba0533684e0b2136817d667588ae3ec984c1a4e5df5eb88482/hatchling-1.27.0-py3-none-any.whl.metadata
    Downloading hatchling-1.27.0-py3-none-any.whl.metadata (3.8 kB)
  Downloading hatchling-1.27.0-py3-none-any.whl (75 kB)
…
Generator: hatchling 1.27.0

The same file passed as an ordinary constraint has no effect on the build in pip 26.2:

PIP_CONSTRAINT=build-constraints.txt python -m pip wheel --no-deps --no-cache-dir -w wh ./birdtally
unzip -p wh/*.whl '*/WHEEL' | grep Generator
Generator: hatchling 1.32.4

The history matters when you upgrade pip:

  • Before 25.3, the only way to influence build dependencies was PIP_CONSTRAINT, which (because it is an environment variable) leaked into the build subprocesses.

  • pip 25.3 added --build-constraint and deprecated relying on PIP_CONSTRAINT for builds; --use-feature=build-constraint opted in to the new behaviour early.

  • pip 26.2 made it the only behaviour: constraints files, including PIP_CONSTRAINT, no longer affect isolated build environments, and --use-feature=build-constraint is accepted but does nothing.

If a CI pipeline pinned setuptools or Cython for builds through PIP_CONSTRAINT, it silently stopped doing so with 26.2; move the pins to PIP_BUILD_CONSTRAINT. Build constraints do not apply with --no-build-isolation, where you install the build dependencies yourself.

pip and Poetry

Poetry has no constraints files: everything the project may install is resolved together and pinned in poetry.lock. The closest equivalents are a direct dependency with a tight constraint in a dedicated group (which does install the package) and, for build dependencies of sdists, installer.build-config-settings for backend settings. poetry export -f constraints.txt (plugin-export) exports the lock for pip users.