pip now has a command that creates a lock file. Run it for requests and it
writes a file named pylock.toml.
$ pip lock requests -o pylock.toml
pylock.toml is the standard Python lock-file format defined by
PEP 751. Poetry has used poetry.lock,
pipenv Pipfile.lock, PDM pdm.lock, and uv uv.lock, with no guarantee that
another tool can read the same file. PEP 751 standardizes the format that tools
write and consume.1
pip can create the file with pip lock and install it with
pip install -r pylock.toml. Both features are still experimental. The pip
behavior described below is from 26.1.2.
Lock formats differed by tool
A lock file records not only the package versions to install but the actual distribution files to use, so development, CI, and production can install the same package set from it.
requirements.txt has long been used in place of a lock file. pip freeze
records the versions installed in the current environment, and adding hashes
can restrict which files pip accepts. Hashes are not included by default and
require an option, so users may not realize the difference.
Tools such as Poetry and uv covered what requirements files were missing with their own lock formats, but a different format cannot be assumed to work in another tool. With uv’s current adoption this may not look like a major problem, but the real cost is probably on the side that consumes lock files. Dependabot and deployment platforms need separate support for each format when there is no common standard. PEP 751 is meant to reduce that maintenance cost.
The pylock.toml structure
The file created above contains requests and its dependencies. Here is an
excerpt.
lock-version = "1.0"
created-by = "pip"
[[packages]]
name = "certifi"
version = "2026.6.17"
[[packages.wheels]]
name = "certifi-2026.6.17-py3-none-any.whl"
url = "https://files.pythonhosted.org/packages/.../certifi-2026.6.17-py3-none-any.whl"
[packages.wheels.hashes]
sha256 = "2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"
[[packages]]
name = "requests"
version = "2.34.2"
[[packages.wheels]]
name = "requests-2.34.2-py3-none-any.whl"
url = "https://files.pythonhosted.org/packages/.../requests-2.34.2-py3-none-any.whl"
[packages.wheels.hashes]
sha256 = "2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0"
A requirements file usually records a package name and version. This file also
records, under each [[packages]], the wheel url to install and the hashes
to verify it. Instead of choosing files for that version from the index again,
an installer selects a compatible file recorded in the lock.
These are only the basic fields. The standard can use markers to cover multiple environments in one file, and record sdists, VCS sources, local directories, and so on.. See the official example for the details.
The standard install model and pip today
Pip prints an experimental-feature warning both when it creates a lock file and when it installs from one.
$ pip lock requests -o pylock.toml
WARNING: pip lock is currently an experimental command.
It may be removed/changed in a future release without prior warning.
$ pip install --dry-run -r pylock.toml
WARNING: Using pylock.toml as a requirements source is an experimental feature.
It may be removed/changed in a future release without prior warning.
Collecting requests==2.34.2 (from pylock.toml)
Would install requests-2.34.2 ...
The install model in PEP 751 and pip’s current implementation are different.
The PEP 751 installation procedure does not search for another combination of package versions. An installer checks environment markers and the Python version, selects the matching package entries and files, verifies their size and hashes, and installs them. The versions and artifacts were already chosen when the lock file was created.
As of pip 26.1, entries from pylock.toml go into the existing resolver like
any other requirements input, but each package’s candidates are limited to the
sdist and wheels recorded in the lock file. The resolver still runs, but it does
not search an index for other versions and distribution files. The pip
maintainers describe this behavior in the
-r pylock.toml issue.
In a direct pip install --dry-run measurement, pylock.toml was faster.2
Current pip 26.1 still sends both inputs through the existing resolver, so the
difference cannot be attributed to whether the resolver runs. pylock may leave
a smaller search space because candidates are limited to the recorded files, but
with this many variables, this measurement alone cannot tell where the speed
difference comes from.
What pip supports today
PEP 751 is Final, but pip’s support for pip lock and -r pylock.toml is still
experimental. The commands and features pip uses to provide the specification
may still change.
At present, pip lock only creates a lock file for the Python version and
platform where it runs. Its help text says this directly.
The generated lock file is only guaranteed to be valid for
the current python version and platform.
The standard can use environments, extras, and dependency-groups to
represent multiple environments and install choices in one file. pip cannot
create a multiplatform lock yet, and it does not emit extras or dependency-group
information. Its installation interface cannot select extras or dependency
groups from a lock file either. The current limits are tracked in the
pip lock issue and the
-r pylock.toml issue.
The format also distinguishes information it can record from information an installer may use.
[[packages.dependencies]]can record relationships between packages. It is for auditing and analysis, and installers must not use it to select packages.- Build requirements needed for an sdist are not locked. PEP 751 left that to a later PEP.
- Requirements-file features such as
-rincludes, environment-variable expansion, and--index-urlare not part of pylock. A requirements file is input to resolution, while pylock records its result.
References
- PEP 751: A file format to record Python dependencies for installation reproducibility
- pylock.toml Specification (PyPA specs)
- pip documentation,
pip lock - What’s next for
pip lock? (pypa/pip#13953) - What’s next for
-r pylock.toml? (pypa/pip#13952)
Footnotes
-
This wasn’t the first attempt at a standard. PEP 665 (2021) was rejected for supporting wheels only. PEP 751, a broader spec that also covers other sources like sdists, was accepted in its place. See PEP 665. ↩
-
With a warm cache, the median of 12 runs was 276 ms for the requirements file and 183 ms for
pylock.toml. This used--dry-run, so it did not include installing the files and does not represent E2E install time. ↩