Skip to content

nox: Python Test Automation Tool

nox manages Python virtual environments and runs tests across multiple Python versions and configurations. Where tox 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 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 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 sufficient without a separate tool; see Do you still need tox or nox if you use uv? 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 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, 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:

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:

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

Session dependencies

A session can require other sessions to run first:

@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:

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

# 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 in the Python ecosystem
  • More setup than needed for projects with simple multi-version testing

Learn More

Last updated on