A person triumphantly raises a key in front of a vault labeled pylock.toml, with a rack of colored keys, wooden crates marked with hashes, and a Python chip alongside.

Tool-Agnostic Python Lock Files With PEP 751 and pylock.toml

The Python lock file, pylock.toml, records exact dependencies your project needs so installs come out the same every time. It isn’t the first of its kind, though—most modern package tools already define their own lock formats. This has led to a fragmented landscape where reproducibility is often limited to a single tool’s workflow, with each ecosystem effectively speaking its own lock file dialect.

From this fragmentation comes a shared standard: pylock.toml. Defined in PEP 751, pylock.toml standardizes reproducible dependency management across different tools, eliminating vendor lock-in and fragmented requirements.txt workflows. Its purpose is to capture a fully resolved set of dependencies in a format that every tool can understand.

But doesn’t requirements.txt already do this? Not exactly. requirements.txt isn’t so much a standardized specification as an implementation detail of pip. The Requirements File Format specifies that “requirements files serve as a list of items to be installed by pip, when using pip install.”

Still, both files exist to enumerate dependencies that should end up in an environment. The difference lies in how that information is represented, either as tool-specific instructions or as a structured, tool-agnostic record of a resolved state:

If you… pylock.toml requirements.txt
Want to share a single lock file with teammates who use different tools (uv, pip, pdm)
Need reproducible, hash-verified installs in CI
Want to install without resolving dependencies on the machine
Need to pass pip flags like --index-url or --no-deps from the file
Want to jot down a couple of dependencies for a quick script by hand

This means pylock.toml is the better choice when you care about reproducibility across tools, the integrity of installed artifacts, or a single shared source of truth that can be consumed in different workflows. It’s especially useful in team settings or continuous integration (CI) pipelines where consistency matters more than manual control.

In contrast, requirements.txt remains a good fit for lightweight workflows, quick experiments, or cases where direct control over pip behavior and flags is more important than cross-tool interoperability or strict locking guarantees.

Take the Quiz: Test your knowledge with our interactive “Tool-Agnostic Python Lock Files With PEP 751 and pylock.toml” quiz. You’ll receive a score upon completion to help you track your learning progress:


Interactive Quiz

Tool-Agnostic Python Lock Files With PEP 751 and pylock.toml

Test your understanding of Python lock files and PEP 751, from generating a pylock.toml with pip to installing it across uv and pdm.

Generating a Python Lock File With pip

With pip version 25.1 or newer, you can generate a pylock.toml file from a requirements.txt file using the experimental pip lock command. At its core, the pylock.toml will serve as a snapshot of every dependency pip would install.

Before you can use pip lock, you’ll need to define a small set of explicit dependencies in a standard requirements file:

Language: Python Requirements Filename: requirements.txt
pandas
scipy

This file expresses only the top-level packages to be installed in your environment. It doesn’t describe how pip resolves those packages or what additional dependencies they need to work.

From here, you can have pip produce a fully resolved lock file:

Language: Shell
$ python -m pip lock --requirement requirements.txt
WARNING: pip lock is currently an experimental command. It may be
⮑ removed/changed in a future release without prior warning.
Collecting pandas (from -r requirements.txt)
  Downloading pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64...
Collecting scipy (from -r requirements.txt)
  Downloading scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64...
Collecting numpy>=2.3.3 (from pandas->-r requirements.txt)
  Downloading numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64...
Collecting python-dateutil>=2.8.2 (from pandas->-r requirements.txt)
  Downloading python_dateutil-2.9.0.post0-py2.py3-none-any...
Collecting six>=1.5 (from python-dateutil>=2.8.2->pandas->-r requirements.txt)
  Downloading six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB)

This triggers the resolution process. pip builds a complete dependency graph starting from the explicit packages (pandas, scipy), resolves all required transitive dependencies, and downloads compatible versions for the current Python environment and platform.

This means the result contains both:

  1. Explicit dependencies: What you specified directly, like pandas and scipy
  2. Transitive dependencies: What those packages require to function, like numpy

You can explore that split for yourself in the interactive graph below. Start with only pandas declared to see the full set it resolves to, then toggle scipy on and watch your two requested packages expand into a larger set of pinned dependencies:

Interactive diagram — enable JavaScript to view.

Pay attention to numpy as you toggle scipy on and off. The install log above attributes numpy to pandas, but scipy depends on it too, so the resolver doesn’t lock it twice—it records a single, shared numpy entry that satisfies both. That’s exactly what a lock file does for you: it turns the short list of packages you asked for into the complete, deduplicated set that will actually be installed.

By capturing the complete dependency graph, pylock.toml enables reproducible and verifiable installations across environments.

Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Article

Already a member? Sign-In

Locked learning resources

The full article is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Article

Already a member? Sign-In

About Cameron Riddell

Cameron is a Python trainer, consultant, and open source maintainer focused on data tools. He teaches Python, SQL, Git, and open science, and he loves the Python community. You'll often find him at events and meetups, so make sure to say hi!

» More about Cameron

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

What Do You Think?

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal.


Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session. Happy Pythoning!

Become a Member to join the conversation.

Keep Learning

Related Topics: intermediate tools