# What is PEP 735?


[PEP 735: Dependency Groups in pyproject.toml](https://peps.python.org/pep-0735/) standardizes how a Python project declares named groups of non-production dependencies. It adds a single `[dependency-groups]` table to [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md) that every packaging tool can read, replacing a patchwork of tool-specific tables that used to hold dev, test, and documentation requirements.

The PEP was authored by Stephen Rosen and resolved on 10 October 2024. It fills a gap in [PEP 621 project metadata](https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility.md), which covered runtime dependencies and end-user extras but said nothing about the dependencies a project needs only during development.

## Fill the gap left by PEP 621

Before PEP 735, every package manager invented its own location for development dependencies. [Poetry](https://pydevtools.com/handbook/reference/poetry.md) used `[tool.poetry.group.dev.dependencies]`. [PDM](https://pydevtools.com/handbook/reference/pdm.md) used `[tool.pdm.dev-dependencies]`. Early [uv](https://pydevtools.com/handbook/reference/uv.md) used `[tool.uv.dev-dependencies]`. Rye used `[tool.rye.dev-dependencies]`. None of these tables were portable: switching package managers meant rewriting project metadata, and a reader could not tell a project's development requirements from the [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md) alone without knowing which tool owned it.

Some projects worked around this by stuffing test and lint dependencies into `[project.optional-dependencies]` as a fake `test` or `dev` extra. That technically worked, but it advertised internal tooling through the package's published metadata, so anyone inspecting the distribution on PyPI saw `pytest` and `ruff` in the user-facing extras list. PEP 735 formalizes a separate, unpublished home for these requirements.

## Declare dependency groups

A dependency group is a named list of requirement strings under the new top-level `[dependency-groups]` table. Each key is the group name and each value is a list following [PEP 508](https://pydevtools.com/handbook/explanation/what-is-a-version-specifier.md) requirement syntax:

```toml
[dependency-groups]
test = [
    "pytest>=8.0",
    "coverage>=7.0",
]
lint = [
    "ruff>=0.15",
    "mypy>=1.0",
]
docs = [
    "sphinx>=9.0",
    "myst-parser>=4.0",
]
```

Groups live outside the `[project]` table on purpose. A project does not need a `[project]` table at all to define dependency groups, so the mechanism works for applications, scripts, and other non-package projects that still benefit from organized tooling requirements.

## Compose groups with include-group

Groups can pull in other groups through the `include-group` directive. This keeps an umbrella group like `dev` in sync with the narrower groups it wraps:

```toml
[dependency-groups]
test = ["pytest>=8.0"]
lint = ["ruff>=0.15"]
typing = ["mypy>=1.0"]
dev = [
    {include-group = "test"},
    {include-group = "lint"},
    {include-group = "typing"},
]
```

Installing the `dev` group now resolves to the union of `test`, `lint`, and `typing`, without duplicating the requirement strings.

## Keep dependency groups separate from extras

PEP 735 draws a hard line between dependency groups and the `[project.optional-dependencies]` extras defined by PEP 621. Extras travel with a package to PyPI and let users opt into runtime features. Dependency groups are invisible to users of the installed package and exist only for people working on the project. The table below summarizes the split, which is explored in depth in [What are Optional Dependencies and Dependency Groups?](https://pydevtools.com/handbook/explanation/what-are-optional-dependencies-and-dependency-groups.md).

|                     | Dependency groups         | Optional dependencies (extras)         |
| ------------------- | ------------------------- | -------------------------------------- |
| Table               | `[dependency-groups]`     | `[project.optional-dependencies]`      |
| Published to PyPI   | No                        | Yes                                    |
| Install audience    | Project developers        | Package users                          |
| Typical contents    | pytest, ruff, sphinx      | numpy, boto3, matplotlib               |

## Install a group

PEP 735 specifies how groups are declared, not a CLI for installing them. Each packaging tool chose its own flag. The common pattern looks like this:

```bash
# uv
uv sync --group test

# pip 25.1+
pip install --group test

# Poetry 2.3+
poetry install --with test

# PDM
pdm install -G test
```

For the full set of [uv](https://pydevtools.com/handbook/reference/uv.md) flags, including `--only-group`, `--all-groups`, `default-groups`, and group conflicts, see [Understanding dependency groups in uv](https://pydevtools.com/handbook/explanation/understanding-dependency-groups-in-uv.md).

## Track tool adoption across the ecosystem

Support for the `[dependency-groups]` table landed across the ecosystem through 2024 and 2025:

- [uv](https://pydevtools.com/handbook/reference/uv.md) 0.4.27 (October 2024) added `[dependency-groups]` reading and writing, with `uv add --group` and `uv sync --group`.
- [pip](https://pydevtools.com/handbook/reference/pip.md) 25.1 (April 2025) introduced the `--group` flag for installing from `pyproject.toml`.
- [Poetry](https://pydevtools.com/handbook/reference/poetry.md) 2.2.0 added reading of `[dependency-groups]` alongside its legacy `[tool.poetry.group.*]` tables. Poetry 2.3.0 fixed lock-file tracking for these groups and is the recommended minimum version.
- [PDM](https://pydevtools.com/handbook/reference/pdm.md) reads `[dependency-groups]` alongside its older `[tool.pdm.dev-dependencies]` table.
- [Hatch](https://pydevtools.com/handbook/reference/hatch.md) 1.16.0 added support for installing from `[dependency-groups]`.

Older tool-specific tables keep working, but new projects should prefer the standard table so the metadata travels cleanly if the project ever changes package managers.

## Learn More

- [PEP 735: Dependency Groups in pyproject.toml](https://peps.python.org/pep-0735/)
- [Dependency Groups specification at packaging.python.org](https://packaging.python.org/en/latest/specifications/dependency-groups/)
- [What are Optional Dependencies and Dependency Groups?](https://pydevtools.com/handbook/explanation/what-are-optional-dependencies-and-dependency-groups.md)
- [Understanding dependency groups in uv](https://pydevtools.com/handbook/explanation/understanding-dependency-groups-in-uv.md)
- [What is PEP 621?](https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility.md)
- [What is PEP 751?](https://pydevtools.com/handbook/explanation/what-is-pep-751.md)
