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.txtkeeps 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
Source: pip user guide: Constraints files.
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.
Source: pip 26.1 changelog, pip: Hash-checking mode.
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-constraintand deprecated relying onPIP_CONSTRAINTfor builds;--use-feature=build-constraintopted 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-constraintis 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.