Tim’s Software Engineering Blog

Getting Started With Requirements Files

You have probably had the experience before of receiving a piece of Python code from someone, and trying to run the code, only to receive a ModuleNotFoundError or an AttributeError stating that a particular module or attribute does not exist. This can be a frustrating experience, as you work your way through the code, gradually finding the required libraries and versions that are needed to get the code to run correctly. Fortunately, there is a simple way to avoid this issue, using a requirements file in every project and script you create.

In this article, we'll cover the basics of what requirements files are, the basic syntax behind them, and why the principle of managing dependencies should be a part of every Python project you work on. Though there are different techniques for managing dependencies with your projects and scripts, using a requirements file is a straightforward and simple approach to making your code more stable and portable.

Table of Contents

What are requirements files?

Requirements files are lists of packages that are installed by pip when running the pip install command and specifying the file name. These files are used not only by pip, but are also forms of documentation for your project, helping other developers get a sense of what your project might be doing at a high level.

A common convention with your requirements file is to name it requirements.txt (or some variation of that), which you will often see in open source projects. For example, here is the requirements-dev.txt file from the Requests library.

Once you have created a requirements file, it is very easy to install all of the requirements using the pip install command. Let's create a very basic requirements file below and install it.

$ echo "pandas" >> requirements.txt
$ pip install -r requirements.txt

And that's it, pip installs everything you need and you are ready to go with your project.

Note: It is considered best practice to use a virtual environment (via venv, virtualenv, or a tool like conda) when installing packages for a project. This helps keep your dependencies isolated and avoids conflicts.

Requirements File Syntax

A requirements file is typically a text file with a series of one or more lines, each containing a specific library that should be installed for your project. A basic example is shown below.

# Sample requirements.txt file
requests
numpy
pandas
scikit-learn

mlflow

You'll see from the example above that you can include comments and blank lines in the file, this can be a helpful way to create logical groupings of requirements or to specify why a particular version was chosen. The full syntax specification of the file can be found here. There are several variations and advanced features for requirements files that can be put in place, but in this article, we'll stick to the basics.

Specifying Versions

Now that we've covered the basics of creating a requirements file and identifying which packages are a part of your requirements, let's take a look at some of the different ways you can specify acceptable versions of listed packages. We'll use our same list of requirements from the previous example and show how you can "pin" specific versions of a package with specifiers.

# Sample requirements.txt file
requests==2.32.5
numpy>=2.0.0
pandas!=1.5.2
scikit-learn
mlflow~=3.0

The Python packaging documentation has specifics on the different syntax that is possible when specifying a version, let's go over them briefly here. We'll start with the most commonly used specifiers and work down to less common syntax.

Specifier Meaning Example
== Exactly this version pandas==2.2.2
>= This version or newer numpy>=1.25.0
<= This version or older scipy<=1.11.2
> Newer than this version numpy>1.25.0
< Older than this version scipy<1.11.2
!= Any version except this one pydantic!=2.3.0
~= Compatible with this version mlflow~=3.0

Managing Dependencies

Having covered the basics of requirements files, their syntax, and specifying versions, you may be thinking that this seems like a lot of work or wondering if there are ways to shortcut this, perhaps through some functionality within pip. It turns out that there is (kind of), but one that comes with some caveats.

Usage of pip freeze

Remember the five packages that we specified before? If you created your own requirements file and installed it using pip, you may have noticed that there were a sizable number of other package dependencies that were installed as well. Running the command pip freeze will show you the full list of packages that are installed in your current environment, along with the versions, in a format similar to our requirements file

$ pip freeze
> alembic==1.16.5
> annotated-types==0.7.0
> anyio==4.10.0
> blinker==1.9.0
> cachetools==5.5.2
> certifi==2025.8.3
# Omitted for brevity...
> requests==2.32.5
> threadpoolctl==3.6.0
> typing-inspection==0.4.1
> typing_extensions==4.15.0
> tzdata==2025.2
> urllib3==2.5.0
> uvicorn==0.35.0
> Werkzeug==3.1.3
> zipp==3.23.0

You might see this as a shortcut to specifying the dependencies in your requirements file, just copy and paste the output in and you're done! But this approach can come with some significant drawbacks that you need to consider before you choose to proceed, some of which I'll go over here.

These examples illustrate tradeoffs that you will need to consider when deciding how flexible or specific you should be for your requirements.

This technique of using pip freeze may be useful in specific, limited contexts, such as deploying a version of your project with Docker, where you have full control over the entire system your project will run on. Another very important scenario where using pip freeze may be warranted is in the context of reproducing research, where being able to run the exact version of the code and libraries used to produce and analyze your data is extremely important.

So, What to Do?

If we feel that using pip freeze has drawbacks in our specific project or script, how do we decide what we need to specify? The guidance that I give newer developers is to only include the packages you explicitly import in your code, and specify version constraints only when necessary. If you're writing a script that uses pandas to do some data manipulation, it's okay to only have the pandas library listed in your requirements file. If you're only using basic functionality of the library, then it's ok to only specify the major version number using one of the version specification techniques we discussed above. This gives you flexibility and simplifies the work that a future developer needs to do to pick up and work with your code.

A Note for the Future

Many newer projects are adopting the usage of a pyproject.toml file to manage their project dependencies, along with other build metadata. The pyproject.toml file is part of a newer standard for specifying packaging and build metadata for Python projects, and is supported by popular tools like Poetry or uv. While this is an excellent approach for your projects, I believe that you should use a requirements file as your minimum acceptable baseline for any project you are working on. If you would like to include more metadata on your project, then using a pyproject.toml file can be an excellent strategy. Here's a sample pyproject.toml file specifying dependencies.

[project]
dependencies = [
  "requests==2.32.5",
  "numpy>=2.0.0",
  "pandas!=1.5.2",
  "scikit-learn",
  "mlflow~=3.0"
]

Whichever method you choose for specifying dependencies, future developers and maintainers will be thankful that you have explicitly documented your development system and runtime expectations.

Further Practice and Reading

Now that we've gone through the basics of requirements files and how they can help you improve your projects, I would encourage you to read through the sources that are listed below. These will help you get a more thorough understanding of how requirements files work and the nuances of different formatting options that will help you more effectively convey your project to other developers and future maintainers.

As a final takeaway, consider the following guidelines for using requirements files.

Sources

#python #requirements #software-engineering