# nox: Python Test Automation Tool

nox manages Python virtual environments and runs tests across multiple Python versions and configurations. Where [tox](https://pydevtools.com/handbook/reference/tox.md) uses declarative TOML or INI configuration, nox uses Python code in a `noxfile.py`, which makes it straightforward to express conditionals, loops, and dynamic session generation. [Hatch](https://pydevtools.com/handbook/reference/hatch.md) offers a third approach with its environment matrix system configured in `pyproject.toml`.

## When to Use nox

nox solves the problem of running test suites, linters, and other checks across multiple Python versions and dependency combinations. Choose nox over [tox](https://pydevtools.com/handbook/reference/tox.md) when test automation logic requires conditionals, loops, or dynamic session generation that declarative configuration cannot express. Projects with straightforward multi-version testing may find [uv's built-in multi-version support](https://pydevtools.com/handbook/how-to/how-to-test-against-multiple-python-versions-using-uv.md) sufficient without a separate tool; see [Do you still need tox or nox if you use uv?](https://pydevtools.com/handbook/explanation/do-you-still-need-tox-or-nox-if-you-use-uv.md) for guidance.

## Key Features

- Python-based configuration: test sessions are defined as functions in a `noxfile.py`, with full access to conditionals, loops, and dynamic session generation
- Session dependencies: the `requires` parameter lets a session declare that other sessions must run first
- uv backend: set `venv_backend='uv'` (or `'uv|virtualenv'` for fallback) to use [uv](https://pydevtools.com/handbook/reference/uv.md) for environment creation and package installation
- pyproject.toml helpers: `nox.project.load_toml()`, `nox.project.dependency_groups()`, and `nox.project.python_versions()` read dependency and version data from `pyproject.toml` so the noxfile stays in sync with project metadata
- PEP 723 noxfile dependencies: noxfiles can declare their own dependencies using [inline script metadata](https://pydevtools.com/handbook/explanation/what-is-pep-723.md), so plugins and helper libraries install automatically
- Multi-version testing: runs sessions against multiple Python versions
- Parallel execution: runs sessions concurrently with `--parallel` to speed up CI
- Parametrization: reuses session logic across configurations with `@nox.parametrize`

## Configuration

Sessions are defined with the `@nox.session` decorator:

```python {filename="noxfile.py"}
import nox

@nox.session(python=["3.11", "3.12", "3.13", "3.14"])
def tests(session):
    session.install("pytest")
    session.run("pytest")
```

Set defaults at the module level with `nox.options`:

```python
nox.options.default_venv_backend = "uv"
nox.options.reuse_venv = "yes"
```

### Session dependencies

A session can require other sessions to run first:

```python
@nox.session
def lint(session):
    session.install("ruff")
    session.run("ruff", "check", ".")

@nox.session(requires=["lint"])
def tests(session):
    session.install("pytest")
    session.run("pytest")
```

### Reading from pyproject.toml

`nox.project` provides helpers that keep the noxfile in sync with project metadata:

```python
import nox

pyproject = nox.project.load_toml("pyproject.toml")

@nox.session(python=nox.project.python_versions(pyproject))
def tests(session):
    session.install(*nox.project.dependency_groups(pyproject, "test"))
    session.run("pytest")
```

## Basic Usage

```bash
# Run all default sessions
nox

# Run a specific session
nox -s tests

# Run sessions matching a tag
nox -t lint

# Run sessions in parallel
nox --parallel

# List available sessions
nox --list
```

## Pros

- Python-based configuration handles logic that declarative formats cannot express
- Session dependencies (`requires`) let complex pipelines run in the right order
- uv backend integration for fast environment creation and installs
- `nox.project` helpers keep the noxfile in sync with `pyproject.toml` metadata
- Active maintenance with calendar-versioned releases

## Cons

- Requires Python knowledge to configure effectively
- Less standardized than [tox](https://pydevtools.com/handbook/reference/tox.md) in the Python ecosystem
- More setup than needed for projects with simple multi-version testing

## Learn More

- [How to test against multiple Python versions using uv](https://pydevtools.com/handbook/how-to/how-to-test-against-multiple-python-versions-using-uv.md)
- [Do you still need tox or nox if you use uv?](https://pydevtools.com/handbook/explanation/do-you-still-need-tox-or-nox-if-you-use-uv.md)
- [pytest](https://pydevtools.com/handbook/reference/pytest.md) reference page
- [tox](https://pydevtools.com/handbook/reference/tox.md) reference page
- [uv](https://pydevtools.com/handbook/reference/uv.md) reference page
- [nox Documentation](https://nox.thea.codes/)
- [nox Configuration & API](https://nox.thea.codes/en/stable/config.html)
- [GitHub Repository](https://github.com/wntrblm/nox)
