Safeguard
Developer Tools•

requirements.txt or project dependencies: abstract vs concrete

Project metadata lists what code needs in loose terms, while a requirements file lists exact installs. Learn the split and why you usually need both.

Safeguard Security Team
3 min read

Your project's dependency list is abstract: names and version limits that say what the code minimally needs. A requirements file is concrete: it can name exact versions and even the index to fetch from. Libraries need the first, deployed applications also need the second.

The distinction in the packaging guide

The Python Packaging User Guide calls the install requirements of a package a listing of abstract requirements, just names and version restrictions, with no source named. Where packages come from is decided at install time with pip options.

Requirements files do the opposite. They list pip install arguments and often include options such as an index URL or a link location, which the guide says make requirements concrete.

Comparison

Project dependency listrequirements.txt
ScopeOne projectOften a whole environment
StrictnessMinimal, avoid exact pinsOften an exhaustive list of pinned versions
Read whenpip installs the project, automaticallySomeone runs install with the requirements file
Names a sourceNoCan

The guide page describes the older setup script keyword, so check your own tool's documentation for how modern project files behave. The idea carries over, but the details are the tool's to state.

The common pattern

  1. Write loose ranges in the project file, tested lower bounds, and upper bounds only where you know of a break.
  2. Generate a fully pinned file or lock from those ranges for deployment.
  3. Install production from the pinned file, ideally with hashes.
  4. Rebuild the pinned file on purpose, in a pull request that someone reviews.

If you only keep the loose list, every deploy resolves afresh and can differ. If you only keep the pinned file, your library tells other people exactly one version of everything, which breaks their builds.

Why the concrete file is a security control

An exact pin means a new upload under the same name cannot enter your build silently. Add hashes and a swapped file under the same version fails as well. The loose list gives you neither. See pinning Python dependencies: requirements.txt vs Poetry and pip-tools lock files for the tool choices.

A small worked example

Say your service imports a web library and a database driver. Your project file says the web library at a tested minimum and the driver at a compatible range. A lock tool resolves those and the packages they need, perhaps thirty in total, into one pinned file with hashes. Your Dockerfile installs from that pinned file only. When someone adds a package, the project file changes by one line and the pinned file by many, and both appear in the same pull request for review.

Quick check

Can I use requirements.txt instead of project metadata for a library?

Not well. A published library needs abstract requirements that installers read automatically.

Should a deployed app have loose ranges only?

No. It also needs a pinned file, so each deploy installs the same set.

Safeguard's SBOM and dependency scanning reads either file, and a free scan takes your manifest.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.