Blog
3 min read

requirements.txt Explained: Python Dependencies for Beginners

requirements.txt lists the Python packages a project needs so anyone can install them with one command. How to create and install it, pinning versions, pip freeze vs writing it by hand, dev requirements, and when to use pyproject.toml with uv or Poetry instead.

A Python project usually depends on packages other people wrote — requests, flask, pandas. requirements.txt is a plain text file listing them, so anyone (including a server) can install exactly what the project needs with one command. (What is Python?)

It's Python's rough equivalent of JavaScript's package.json. (What are npm and package.json?)

What it looks like

flask==3.1.1
gunicorn==23.0.0
psycopg[binary]==3.2.9
python-dotenv==1.1.0
requests>=2.32,<3

One package per line, optionally with a version rule.

Installing from it

Inside your project's virtual environment:

python -m pip install -r requirements.txt

(Python virtual environments)

Creating it

Option 1: pip freeze

python -m pip freeze > requirements.txt

Writes every package installed in the current environment, with exact versions — including dependencies of your dependencies.

  • ✅ Fully reproducible: the same versions everywhere.
  • ❌ Includes everything in the environment — if you installed something to try it, it's in there. Run it from a clean virtual environment used only for this project.

Option 2: write it by hand

List only the packages you use directly:

flask>=3.1,<4
requests>=2.32,<3
  • ✅ Short and readable.
  • ❌ Sub-dependencies can change between installs, so two machines may end up slightly different.

A common middle ground: keep a short hand-written requirements.in and generate a fully pinned requirements.txt from it with pip-tools (pip-compile) or uv (uv pip compile).

Version specifiers

Specifier Meaning
flask==3.1.1 Exactly this version
flask>=3.1 This version or newer
flask>=3.1,<4 3.1 or newer, but not 4.x
flask~=3.1.0 Compatible release: 3.1.x
flask Any version — avoid in real projects

Pinning protects you from surprise breaking changes when a package releases a new major version. (Semantic versioning explained)

Separate development requirements

Testing and linting tools don't need to be on your production server:

# requirements-dev.txt
-r requirements.txt
pytest==8.4.0
ruff==0.12.0

-r includes the main file. Install with pip install -r requirements-dev.txt locally.

Common problems

  • ModuleNotFoundError on the server — a package is installed locally but missing from the file. (ModuleNotFoundError)
  • Installing into the wrong Python — use python -m pip, inside the virtual environment.
  • externally-managed-environment — you're not in a virtual environment. (Fix it)
  • Package name ≠ import name — import cv2 needs opencv-python in the file.
  • Platform-specific packages — a pip freeze from Windows may include packages that don't install on Linux (like pywin32).

The modern alternative: pyproject.toml

Newer projects increasingly list dependencies in pyproject.toml, managed by tools like uv or Poetry, with a separate lock file for exact versions:

uv init
uv add flask requests
uv run app.py

This gives you package.json-style management: direct dependencies in one file, exact versions locked in another. requirements.txt is still everywhere, though — hosting platforms and tutorials all understand it, and uv export can produce one.

The summary

  • requirements.txt lists the packages your project needs.
  • Install with python -m pip install -r requirements.txt in a virtual environment.
  • Pin versions; generate with pip freeze from a clean environment, or compile from a short input file.
  • Consider pyproject.toml + uv for new projects.

EasySpawn installs your Python app's requirements into its own environment on every deploy, so what runs on the server is exactly what you listed. See how it works or join the waitlist.

Related: Python Virtual Environments · ModuleNotFoundError · pip "externally-managed-environment" · What Is Python?

Keep reading