# What is PEP 508?


[PEP 508: Dependency specification for Python Software Packages](https://peps.python.org/pep-0508/) defines the standard format for declaring dependencies on Python packages. Every [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md) dependency list and every [pip](https://pydevtools.com/handbook/reference/pip.md) requirement string uses PEP 508 syntax, and so does every [Poetry](https://pydevtools.com/handbook/reference/poetry.md) dependency.

## How a requirement string is built

A PEP 508 requirement string specifies a package name, optional version constraint, optional extras, and optional environment markers:

```
package-name>=1.0,<2.0; extra == 'dev' and python_version >= '3.9'
```

The components are:

1. **Package name**: `requests`, `django`, `numpy`
2. **Version specifier** (optional): `>=1.0`, `==2.3.4`, `~=1.2.3` (see [PEP 440](https://pydevtools.com/handbook/explanation/versioning-python-packages-semver-calver-and-pep-440.md) for syntax)
3. **Extras** (optional): `[dev,test]` to request optional feature bundles
4. **Environment markers** (optional): `;` followed by conditions like `python_version >= '3.9'` or `sys_platform == 'win32'`

## Examples

Pure package dependency:

```
numpy
```

With version constraint:

```
requests>=2.25.0,<3.0
```

With extras (install optional dependencies):

```
flask[async]
```

With multiple extras:

```
pandas[excel,plot]
```

With environment markers (install only on Windows):

```
pywin32; sys_platform == 'win32'
```

With extras and markers:

```
numpy>=1.20; python_version >= '3.9' and extra == 'scientific'
```

## Environment Markers

Markers allow conditional dependencies based on the installation environment:

- `python_version`: active Python version, e.g. `'3.9'`, `'3.10'`
- `sys_platform`: `'linux'`, `'darwin'` (macOS), `'win32'`, etc.
- `platform_machine`: CPU architecture, e.g. `'x86_64'`, `'arm64'`
- `platform_system`: OS name, `'Linux'`, `'Darwin'`, or `'Windows'`
- `implementation_name`: Python implementation, `'cpython'`, `'pypy'`, etc.
- `extra`: the optional-dependency group being installed

PEP 508 also defines `os_name`, `python_full_version`, `platform_release`, and `platform_version`.

## Where PEP 508 Appears

In `pyproject.toml` dependencies:

```toml
[project]
dependencies = [
    "requests>=2.25",
    "dataclasses-json; python_version < '3.7'",
    "typing-extensions; python_version < '3.8'",
]

[project.optional-dependencies]
dev = [
    "pytest>=6.0",
    "mypy; python_version >= '3.8'",
]
```

In `requirements.txt` files:

```
requests>=2.25
numpy>=1.20; python_version >= '3.9'
```

In [pip](https://pydevtools.com/handbook/reference/pip.md) and [uv](https://pydevtools.com/handbook/reference/uv.md) commands:

```bash
pip install 'requests>=2.25,<3.0'
uv add 'numpy>=1.20; python_version >= "3.9"'
```

## Version Specifier vs. Environment Marker

Both specify constraints, but they mean different things:

- **Version specifier** (`>=1.0,<2.0`): which package versions are acceptable
- **Environment marker** (`python_version >= '3.9'`): when to install this dependency (Python version, platform, etc.)

A single requirement can combine both:

```
numpy>=1.20; python_version >= '3.9'
```

This means: "Install numpy 1.20 or later, but only on Python 3.9+. On Python 3.8, ignore this dependency entirely."

## Why one syntax works across tools

Because PEP 508 standardizes the format, pip, uv, Poetry, and Hatch all parse the same dependency strings. A project can switch tools, or use several at once, without rewriting its dependency list for each one.

## Learn More

- [PEP 508 Specification](https://peps.python.org/pep-0508/)
- [PEP 440: Versioning specification](https://pydevtools.com/handbook/explanation/versioning-python-packages-semver-calver-and-pep-440.md) for version specifier syntax
- [pyproject.toml reference](https://pydevtools.com/handbook/reference/pyproject.toml.md)
- [pip requirements file format](https://pip.pypa.io/en/stable/reference/requirements-file-format/)
