# Black: Python Code Formatter

Black is an opinionated Python code formatter that rewrites source files to conform to a strict subset of [PEP 8](https://pydevtools.com/handbook/explanation/what-is-pep-8.md). It exposes few configuration options by design, so teams converge on one canonical style instead of debating formatting choices. To sort imports alongside Black, most projects pair it with [isort](https://pydevtools.com/handbook/how-to/how-to-sort-python-imports-with-ruff.md) (or use [Ruff](https://pydevtools.com/handbook/reference/ruff.md), which bundles both).

## When to use Black

Black fits codebases that already run it in CI or [pre-commit hooks](https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project.md) and have built workflows around its stable output. Its formatting has been the de facto Python standard since 2018, and many editor plugins, linter configs, and CI pipelines assume Black-compatible style.

For new projects, the [Ruff](https://pydevtools.com/handbook/reference/ruff.md) formatter produces nearly identical output, runs 10-100x faster, and bundles linting and import sorting in the same binary. To switch an existing project, see [How to migrate from Black to the Ruff formatter](https://pydevtools.com/handbook/how-to/how-to-migrate-from-black-to-ruff-formatter.md). To consolidate the wider lint stack at the same time, see [How to replace Black, isort, flake8, and pyupgrade with Ruff](https://pydevtools.com/handbook/how-to/how-to-replace-black-isort-flake8-pyupgrade-with-ruff.md).

## Key Features

### Formatting style

Black defaults to 88-character lines, four-space indentation, and double quotes. It adds trailing commas in multi-line constructs, normalizes string prefixes, and collapses or expands expressions to fit the line-length target. The output is deterministic: the same input always produces the same output regardless of the original formatting.

Black follows a yearly stable style cadence. Code formatted in a given calendar year stays unchanged across all releases from that year. Style changes accumulate behind `--preview` and graduate to the next year's stable style. A separate `--unstable` flag exposes experimental changes that may not graduate.

### Configuration

Black reads the `[tool.black]` table in [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md). The available options are deliberately limited: `line-length`, `target-version`, `skip-string-normalization`, `skip-magic-trailing-comma`, file/directory exclusion patterns, `--preview` for changes targeting next year's stable style, and `--unstable` for experimental changes that may not graduate. This scarcity of knobs is the tool's central design choice.

### Integration

Black ships [pre-commit hooks](https://pydevtools.com/handbook/how-to/how-to-set-up-pre-commit-hooks-for-a-python-project.md), editor plugins (VS Code, PyCharm, Vim/Neovim), and a `--check` mode for CI that exits non-zero when files need reformatting. It can also format Jupyter notebooks and exposes a Python API for programmatic use.

The `black[d]` extra installs `blackd`, an HTTP formatting daemon that editors and internal services can call over the network. Ruff offers a language server (`ruff server`) but no HTTP equivalent.

## Pros

- Deterministic output eliminates formatting debates across teams
- Near-zero configuration required for most projects
- Yearly stable style guarantee: code formatted in a given calendar year stays unchanged across all releases from that year
- Broad ecosystem support: most Python linters and editors understand Black-compatible formatting

## Cons

- Does not lint, sort imports, or fix code issues (requires pairing with [flake8](https://pydevtools.com/handbook/reference/flake8.md) for linting or [Ruff](https://pydevtools.com/handbook/reference/ruff.md) for linting and import sorting)
- 10-100x slower than [Ruff](https://pydevtools.com/handbook/reference/ruff.md)'s formatter on large codebases
- The few style choices it makes (double quotes, 88-char lines) cannot be overridden without `skip-string-normalization`, and some choices have no override at all
