Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Black User Guide

Generated June 2026 from psf/black at ce1897a

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Black is the uncompromising Python code formatter. You give it your source files; it rewrites them into a single, deterministic style so you never argue about formatting again. By using Black, you cede control over the minutiae of hand-formatting β€” and in return you get speed, determinism, and freedom from formatting nags. Blackened code looks the same regardless of the project you are reading, which makes diffs smaller and code review faster.

This guide covers everything you need to install Black, format your code, configure it for your project, and integrate it into your editor and CI. Every command, option, and default below is taken directly from Black's source.

Note

Black requires Python 3.10 or newer to run. It can format code targeting much older Python versions (back to 3.3), but the Black process itself needs 3.10+.


1. Quick Start

Install Black and format a file or directory in three steps.

# 1. Install
pip install black

# 2. Format a single file (rewrites it in place)
black your_script.py

# 3. Or format an entire project
black .

When Black finishes, it prints a short summary:

reformatted your_script.py

All done! ✨ 🍰 ✨
1 file reformatted.

If your code was already perfectly formatted, you'll see:

All done! ✨ 🍰 ✨
1 file left unchanged.

Tip

Before letting Black rewrite a whole project, run it in preview mode first to see what would change without touching any files:

black --check --diff .

--check tells you whether anything would change (via the exit code), and --diff prints the exact changes as a unified diff.

That's the whole product. Black is deliberately about sensible defaults β€” if you are asking yourself "do I need to configure anything?", the answer is almost always "no".


2. Installation

Black is distributed on PyPI as the black package. It ships several optional "extras" that pull in additional dependencies for specific features.

Base install

pip install black

Gives you the black and python -m black commands. This is all most users ever need.

Jupyter Notebooks

pip install "black[jupyter]"

Adds support for formatting .ipynb notebook files. Pulls in ipython and tokenize-rt.

Colored output on Windows

pip install "black[colorama]"

Adds colorama so that --color diffs render correctly in the Windows terminal.

Faster startup (uvloop)

pip install "black[uvloop]"

Installs uvloop (Linux/macOS) or winloop (Windows) for a faster event loop when formatting many files in parallel.

Format server (blackd)

pip install "black[d]"

Installs aiohttp and enables the blackd HTTP formatting server (see Section 8).

You can combine extras: pip install "black[jupyter,colorama]".

Verify the installation

black --version
black, 25.x.x (compiled: yes)
Python (CPython) 3.12.6

The compiled: yes/no field tells you whether you installed a mypyc-compiled build. Compiled builds run significantly faster; the pure-Python build behaves identically but is slower.

Note

If running black as a script doesn't work (for example, the entry point isn't on your PATH), you can always invoke it as a module:

python -m black your_script.py

Run Black without installing it

If you just want to format something once, pipx and uvx let you run Black in a throwaway environment:

pipx run black .
# or
uvx black .

3. Everyday Usage

Black's core job is simple: point it at code, and it reformats that code.

Format files and directories

You can pass any mix of files and directories. Black walks directories recursively, finding every .py, .pyi, and .ipynb file.

black src/ tests/ setup.py
reformatted src/app/models.py
reformatted tests/test_models.py

All done! ✨ 🍰 ✨
2 files reformatted, 14 files left unchanged.

Tip

Black is safe to run repeatedly. It is idempotent: running it on already-formatted code changes nothing. There's no harm in formatting your whole project on every commit.

Format code from a string

Use -c / --code to format a snippet directly, printing the result to stdout. This never touches any file.

black -c "def f(x:int=1)->None: print( x )"
def f(x: int = 1) -> None:
    print(x)

Format from standard input

Pass - as the source to read from stdin and write the formatted result to stdout. This is how most editor plugins talk to Black.

cat your_script.py | black -

Important

When reading from stdin, Black can't see the filename, so it can't honor --force-exclude or pick the right mode for .pyi/.ipynb files. Use --stdin-filename to tell Black what the file is really called:

cat stub.pyi | black --stdin-filename=stub.pyi -

Preview changes without writing them

You want to… Command Effect
See if anything would change black --check . Writes nothing. Exit code 0 = no changes needed, 1 = changes needed.
See exactly what would change black --diff . Prints a unified diff to stdout. Writes nothing.
Both, with color black --check --diff --color . Colored diff + status exit code.
black --check --diff src/app/models.py
--- src/app/models.py	2026-06-05 12:00:00.000000+00:00
+++ src/app/models.py	2026-06-05 12:00:01.000000+00:00
@@ -1,3 +1,3 @@
-def f(x:int=1)->None:
-    print( x )
+def f(x: int = 1) -> None:
+    print(x)
would reformat src/app/models.py

Oh no! πŸ’₯ πŸ’” πŸ’₯
1 file would be reformatted.

Tip

--check is the option you want in continuous integration. It fails the build (exit code 1) when someone forgot to run Black, without modifying any files. See Section 7.

Control the output volume

Option Behavior
-v / --verbose Report files that were left unchanged or skipped, and which config file is in use.
-q / --quiet Suppress all non-critical output. Error messages still appear (silence them with 2>/dev/null).

4. Common Tasks (Recipes)

Format only specific line ranges

When you only want to format the lines you actually touched β€” useful for gradually adopting Black on a large legacy file β€” use --line-ranges. Ranges are 1-based and inclusive on both ends, given as START-END. Repeat the option to format multiple ranges.

black --line-ranges=10-20 --line-ranges=45-50 legacy_module.py

Warning

--line-ranges only works on a single file at a time and is incompatible with Jupyter notebooks (--ipynb). Black will exit with an error if you combine it with multiple files.

Skip formatting a region of code

Black reads special comment directives in your source. These let you opt specific code out of formatting:

Directive Effect
# fmt: off Stop formatting from this line onward.
# fmt: on Resume formatting (pairs with a preceding # fmt: off).
# fmt: skip Leave this one line/statement exactly as written.
# fmt: off
custom_matrix = [
    1, 0, 0,
    0, 1, 0,
    0, 0, 1,
]
# fmt: on

WIDE_TABLE = {'a': 1,  'b': 2,   'c': 3}  # fmt: skip

Note

For compatibility, Black also recognizes YAPF's # yapf: disable and # yapf: enable as aliases for # fmt: off and # fmt: on. Both spellings with and without a space after the colon work (# fmt:off and # fmt: off).

Keep a collection exploded with the magic trailing comma

If you add a trailing comma to a bracketed collection, Black treats that as a signal that you want it expanded one-item-per-line, and it won't collapse it back:

# You write this (note the trailing comma after "three"):
COLORS = ["one", "two", "three",]

# Black keeps it exploded:
COLORS = [
    "one",
    "two",
    "three",
]

Remove the trailing comma and Black will collapse short collections back onto one line. To disable this behavior entirely, pass -C / --skip-magic-trailing-comma.

Format Jupyter notebooks

With the jupyter extra installed, Black formats the Python code cells inside .ipynb files, automatically masking IPython magics (%timeit, !ls, etc.) so they don't break parsing.

black notebooks/analysis.ipynb

To treat input piped on stdin as a notebook regardless of its extension, add --ipynb. To teach Black that a custom cell magic contains Python (so it formats the cell body), use --python-cell-magics:

black --python-cell-magics=my_magic --python-cell-magics=custom notebook.ipynb

Format typing stub (.pyi) files

Black automatically formats .pyi files using stub-specific rules (e.g. different blank-line conventions). To force stub formatting on stdin or non-.pyi files, pass --pyi.

Require everyone to use the same Black version

Different Black releases can format code slightly differently. To guarantee everyone on a team uses the same version, set --required-version. Black exits with an error if the running version doesn't match:

black --required-version=25.1.0 .

This is best set in your pyproject.toml (see Section 5) so it applies everywhere automatically.

Go faster on large codebases

Option Effect
-W / --workers N Use N parallel worker processes (default: number of CPUs).
--fast Skip the post-format AST safety check (faster, slightly riskier).
--no-cache Ignore the cache and reformat every file (mostly for debugging).
black --workers=8 .

Tip

Black caches formatting results, so the second run over an unchanged project is nearly instant. You rarely need --no-cache.


5. Configuration

Black is "all about sensible defaults", but you can override them per-project. Black reads its default option values from a pyproject.toml file, so you set them once and every team member and CI run picks them up automatically.

The [tool.black] section

Put a [tool.black] table in your pyproject.toml. The keys are the long names of the command-line options, with dashes replaced by underscores (or kept as dashes β€” both are accepted).

[tool.black]
line-length = 100
target-version = ["py310", "py311", "py312"]
skip-string-normalization = false
extend-exclude = '''
/(
    migrations
    | build
)/
'''

The table below maps every configurable CLI option to its pyproject.toml key and default.

CLI option pyproject.toml key Default Meaning
--line-length line-length 88 Maximum characters per line.
--target-version target-version auto-detected Python versions your output must support (a list).
--skip-string-normalization skip-string-normalization false Keep your original quote style instead of preferring double quotes.
--skip-magic-trailing-comma skip-magic-trailing-comma false Ignore trailing commas as a split signal.
--skip-source-first-line skip-source-first-line false Leave the first line of each file untouched.
--preview preview false Opt into upcoming stable-style changes.
--unstable unstable false Opt into preview plus known-buggy experimental changes.
--include include (\.pyi?|\.ipynb)$ Regex of filenames to include in recursive search.
--exclude exclude (see below) Regex of paths to exclude (overrides the defaults).
--extend-exclude extend-exclude β€” Regex of paths to exclude in addition to the defaults.
--force-exclude force-exclude β€” Like exclude, but also applies to paths passed explicitly.
--required-version required-version β€” Fail unless this Black version is running.
--workers workers CPU count Number of parallel worker processes.

Important

In TOML, regular expressions must use single-quoted strings (the equivalent of Python raw strings), and multi-line strings are treated as verbose regexes (whitespace and # comments are ignored). This is why the extend-exclude example above is formatted across several lines.

Warning

--line-ranges cannot be set in pyproject.toml β€” it only makes sense per-invocation. Black raises an error if it finds a line_ranges key in your config file.

How Black finds your configuration

Black locates the project root by walking up from the files you passed, looking for the first directory that contains any of:

  1. A .git directory
  2. A .hg directory
  3. A pyproject.toml file that contains a [tool.black] section

It then reads pyproject.toml from that root. Run with -v to see which root and config file Black chose:

black -v .
Identified `/home/you/project` as project root containing a pyproject.toml.
Using configuration from project root.

You can point at a specific config file with --config:

black --config=/path/to/black.toml src/

If no project-level config is found, Black falls back to a user-level config file:

  • Windows: ~\.black
  • macOS / Linux: ~/.config/black (or $XDG_CONFIG_HOME/black if set)

Target version auto-detection

If you don't set target-version, Black tries to figure out which Python versions your output must support:

  1. First, it reads requires-python from the [project] table of your pyproject.toml (the PEP 621 metadata).
  2. If that's inconclusive, it auto-detects per file based on the syntax features each file actually uses.

So in a well-formed modern project, you usually don't need to set target-version at all.

Tip

Setting target-version explicitly is still worthwhile when you want Black to use newer formatting (like trailing commas after *args) that's only safe on certain Python versions. List every version your code supports, e.g. ["py310", "py311"].

Invalid config keys

If you misspell a key in [tool.black], Black warns you but continues:

Invalid config keys detected: 'line_lenght' (in /home/you/project/pyproject.toml)

6. Editor & Version Control Integration

pre-commit

Black ships pre-commit hooks. Add this to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/psf/black-pre-commit-mirror
    rev: 25.1.0   # use the version you pin
    hooks:
      - id: black
        # For Jupyter notebooks, use this hook instead:
        # - id: black-jupyter

Tip

Black recommends the dedicated psf/black-pre-commit-mirror repository rather than hooking psf/black directly. The mirror runs about 2Γ— faster because it doesn't have to build Black from source.

The two available hook IDs are:

Hook ID Formats
black .py and .pyi files
black-jupyter .py, .pyi, and .ipynb files (installs the jupyter extra automatically)

Editors

Most editors integrate by piping the buffer through black - (with --stdin-filename set so excludes are respected). Black is also commonly driven through the Language Server Protocol via companion projects. Consult your editor's Python tooling docs; the underlying command is always the same black - stdin invocation shown in Section 3.

Show your style

Let people know your project uses Black with the badge:

[Code style: black](https://github.com/psf/black)

7. Continuous Integration

The official GitHub Action

Black publishes a GitHub Action. In a workflow:

- uses: psf/black@stable
  with:
    options: "--check --diff"
    src: "./src"

The Action accepts these inputs:

Input Default Description
options "--check --diff" Options passed to Black.
src "." Paths to format.
jupyter false Set true to also format Jupyter notebooks.
version (latest) A PEP 440 version specifier, e.g. "25.1.0".
use_pyproject false Read the Black version from your pyproject.toml instead.
summary true Add Black's output to the GitHub job summary.
output-file β€” Also write Black's output to a file (keeps logs clean when using --diff).
black_args β€” Deprecated. Use options + src instead.

Important

version and use_pyproject are mutually exclusive β€” set one or the other, not both. The Action will fail if you provide both.

Exit codes

Black's exit code is what makes CI work. Use it directly in any CI system:

Exit code Meaning
0 Success. With --check: nothing would be reformatted.
1 With --check: one or more files would be reformatted.
123 An internal error occurred while processing a file.
# Typical CI step
black --check --diff . || exit 1

8. The blackd Format Server

blackd is a small HTTP server that formats code on demand. It's intended for editor and tooling integrations that want to avoid paying Black's startup cost on every keystroke. It requires the d extra (pip install "black[d]").

Start the server

blackd --bind-host=localhost --bind-port=45484
blackd version 25.x.x listening on localhost port 45484
Option Default Description
--bind-host localhost Address to bind to.
--bind-port 45484 Port to listen on.
--cors-allow-origin β€” An origin allowed to access blackd via CORS. Repeat for multiple origins.
--max-body-size 5242880 (5 MiB) Maximum request body size in bytes.

Make a request

Send the unformatted code as the raw POST / body. Formatting options are passed as X-* request headers.

curl -s -XPOST "http://localhost:45484" \
  -H "X-Line-Length: 100" \
  -H "X-Skip-String-Normalization: yes" \
  --data-binary @your_script.py

The response carries the formatted code, plus an X-Black-Version header.

Request headers (all optional):

Header Corresponds to
X-Protocol-Version Must be 1 (the only supported version).
X-Line-Length --line-length
X-Python-Variant --target-version (e.g. py3.10,py3.11), or pyi.
X-Skip-Source-First-Line --skip-source-first-line
X-Skip-String-Normalization --skip-string-normalization
X-Skip-Magic-Trailing-Comma --skip-magic-trailing-comma
X-Preview --preview
X-Unstable --unstable
X-Enable-Unstable-Feature --enable-unstable-feature (comma-separated).
X-Fast-Or-Safe fast to skip the safety check.
X-Diff Return a unified diff instead of the formatted code.

Response status codes:

Status Meaning
200 Code was reformatted; body is the result.
204 Input was already well-formatted; nothing returned.
400 Input had a syntax error, or a header was invalid.
500 An unexpected error occurred while formatting.
501 Requested protocol version is not supported.

Caution

blackd performs no authentication. Bind it to localhost (the default) and never expose it directly to an untrusted network. Use --cors-allow-origin only for the specific browser origins you trust.


9. The Black Code Style (What to Expect)

Black is a PEP 8–compliant, opinionated formatter. It reformats entire files in place and deliberately offers very few style knobs. A few highlights of what it does:

  • Line length defaults to 88 characters β€” a deliberate ~10% increase over PEP 8's 79, found to reduce total lines without hurting readability.
  • Strings are normalized to double quotes ("like this"), unless that would require more escaping. Disable with -S.
  • Magic trailing comma: a trailing comma forces a collection to stay expanded (see Section 4).
  • Smallest diffs: Black aims to produce the minimal change, so code review focuses on content, not formatting.

Note

Black is intentionally stable. Now that it has reached maturity, you should not expect large formatting changes between releases β€” stylistic changes are mostly responses to bug reports and support for new Python syntax. New ideas land behind --preview first.

Preview and unstable styles

Black gates experimental formatting behind two flags so it can gather feedback before making changes permanent:

Flag What it enables
--preview Potentially disruptive changes likely to become part of the next stable release.
--unstable Everything in --preview, plus changes with known bugs. Implies --preview.
--enable-unstable-feature NAME Turn on one specific experimental feature. Requires --preview.

Warning

No compatibility guarantees are made for --unstable or individually enabled unstable features β€” their behavior and even their existence can change between releases. Don't depend on them in shared configuration unless you accept churn.

The safety check

By default (--safe), after formatting a file Black re-parses both the original and the result and confirms they produce an equivalent abstract syntax tree, and that a second formatting pass wouldn't change anything. If either check fails, Black aborts with an internal-error message and a link to file a bug β€” it will never knowingly write code that means something different from your original. Pass --fast to skip these checks when you value speed over the extra guarantee.


10. Complete CLI Reference

Every option of the black command, taken directly from the source.

Option Argument Description
SRC ... paths Files/directories to format. Use - for stdin.
-c, --code TEXT Format the code passed as a string and print the result.
-l, --line-length INT Characters per line allowed. Default 88.
-t, --target-version py33…py315 Python version(s) the output must support. Repeatable.
--pyi flag Format input as typing stubs regardless of extension.
--ipynb flag Format input as Jupyter notebooks regardless of extension.
--python-cell-magics TEXT Treat this notebook cell magic as containing Python. Repeatable.
-x, --skip-source-first-line flag Don't format the first line of the file.
-S, --skip-string-normalization flag Don't normalize string quotes or prefixes.
-C, --skip-magic-trailing-comma flag Don't use trailing commas as a reason to split lines.
--preview flag Enable upcoming stable-style changes.
--unstable flag Enable preview + known-buggy changes. Implies --preview.
--enable-unstable-feature NAME Enable one specific unstable feature. Requires --preview. Repeatable.
--check flag Don't write; exit 0/1 based on whether changes are needed.
--diff flag Don't write; print a unified diff to stdout.
--color / --no-color flag Show (or hide) colored diff. Only applies with --diff.
--line-ranges START-END Format only these 1-based inclusive line ranges. Repeatable. Single file only.
--fast / --safe flag Skip (or run) the post-format AST safety check. Default --safe.
--required-version TEXT Fail unless this exact Black version is running.
--exclude REGEX Paths to exclude on recursive search (overrides defaults).
--extend-exclude REGEX Paths to exclude in addition to the defaults.
--force-exclude REGEX Like --exclude, but also applies to explicitly-passed paths.
--stdin-filename TEXT The filename to assume for stdin input.
--include REGEX Paths to include on recursive search. Default (\.pyi?|\.ipynb)$.
-W, --workers INT Number of parallel worker processes. Default: CPU count.
--config PATH Read options from this configuration file.
--no-cache flag Skip reading/writing the cache; reformat everything.
-q, --quiet flag Suppress non-critical output.
-v, --verbose flag Report unchanged/skipped files and the config in use.
--version flag Show version (and whether it's compiled) and exit.
-h, --help flag Show help and exit.

Environment variables

Variable Effect
BLACK_CACHE_DIR Override where Black stores its formatting cache.
BLACK_NUM_WORKERS Set the default number of parallel workers (same as --workers).
XDG_CONFIG_HOME On Unix, where Black looks for the user-level config ($XDG_CONFIG_HOME/black).

11. Troubleshooting

Error: One of 'SRC' or 'code' is required.

Cause: You ran black with no files and no -c. Solution: Pass a path (black .), a file, - for stdin, or -c "code". Prevention: In scripts and CI, always pass an explicit path.

Error: 'SRC' and 'code' cannot be passed simultaneously.

Cause: You combined a path argument with -c/--code. Solution: Use one or the other β€” format files or a string, not both at once.

Message: No Python files are present to be formatted. Nothing to do 😴

Cause: Every file under the given path was excluded β€” by .gitignore, the default excludes, your --exclude/--extend-exclude patterns, or because none matched --include. Solution: Run with -v to see exactly which paths were skipped and why. Check your exclude regex and whether the directory is in .gitignore. Prevention: Remember Black ignores .gitignored paths and a built-in list of virtualenv/build directories by default.

Error: Cannot pass both 'pyi' and 'ipynb' flags!

Cause: --pyi and --ipynb are mutually exclusive. Solution: Pick the one that matches your input.

Error: '--enable-unstable-feature' requires '--preview'.

Cause: You enabled an unstable feature without --preview (or --unstable). Solution: Add --preview (or use --unstable, which implies it).

Error: The required version ... does not match the running version ...!

Cause: --required-version (or the required-version config key) doesn't match the installed Black. Solution: Install the required version, e.g. pip install black==25.1.0, or update the requirement.

Warning about Python 3.12.5

Cause: Python 3.12.5 has a memory-safety bug that can break Black's AST safety check. Solution: Upgrade to Python 3.12.6 or downgrade to 3.12.4. Black exits rather than risk an unsafe check.

Error: cannot use --safe with this file; failed to parse source file AST

Cause: Your source uses syntax that the Python running Black can't parse (often because you're running Black on an older Python than your code targets). Solution: Run Black on a newer Python, set --target-version to match, or use --fast to skip the equivalence check.

INTERNAL ERROR: Black produced code that is not equivalent... / ...different code on the second pass...

Cause: A genuine bug in Black β€” the safety check caught it before any bad output was written. Solution: This is rare. The message includes a path to a dump file and a link to file a bug. Please report it with the diff. Your original file is left untouched.

Error: File '...' cannot be parsed as valid Jupyter notebook.

Cause: A .ipynb file is malformed or isn't actually JSON. Solution: Open it in Jupyter to repair it, or exclude it.

blackd: 400 Invalid line length header value

Cause: X-Line-Length wasn't an integer. Solution: Send a numeric value, e.g. X-Line-Length: 88.

blackd: 400 with 3.x is not supported / major version must be 2 or 3

Cause: The X-Python-Variant header named an unsupported version (Black supports Python 3 only). Solution: Use values like py3.10, 3.11, or pyi.


12. FAQ

Q: Do I need to configure anything to get started? No. Black is designed around sensible defaults. Just run black .. Reach for pyproject.toml only when you have a genuine reason, like a non-standard line length.

Q: Will Black ever change what my code does? No. By default Black runs an AST-equivalence check after formatting and refuses to write output that isn't semantically identical to your input. The only way to skip that check is to explicitly pass --fast.

Q: Why is the default line length 88 and not 79? It's a deliberate ~10% bump over PEP 8's 79, which the maintainers found reduces total line count meaningfully without hurting readability. You can change it with --line-length.

Q: Can I make Black leave my single quotes alone? Yes β€” pass -S / --skip-string-normalization (or set skip-string-normalization = true). Otherwise Black prefers double quotes.

Q: How do I stop Black from touching one specific block? Wrap it in # fmt: off … # fmt: on, or put # fmt: skip at the end of a single line.

Q: How do I exclude a directory? Black already skips .gitignored paths and common virtualenv/build folders. For anything else, use --extend-exclude (to add to the defaults) or --exclude (to replace them). Remember these are regexes.

Q: Does Black format my whole repo even files I didn't change? If you point it at ., yes β€” it formats every discovered Python file. To format just changed lines, use --line-ranges; to format just changed files, pass those files explicitly (often combined with --force-exclude in pre-commit hooks).

Q: Why is Black skipping my .ipynb files? You need the Jupyter extra: pip install "black[jupyter]". Without it, notebooks are silently skipped (run with -v to see the notice).

Q: My CI passes locally but fails in the pipeline. Why? Different Black versions format slightly differently. Pin the version everywhere (in pyproject.toml, pre-commit rev, and the GitHub Action version/use_pyproject), or set --required-version.

Q: Is there a way to run Black faster? Use more workers (-W), install the uvloop extra, and rely on the cache (don't pass --no-cache). For editor integrations, run the blackd server to avoid repeated startup cost.

Q: What do the exit codes mean? 0 = all good, 1 = files would be reformatted (under --check), 123 = an internal error occurred.

Q: What Python versions can Black format? Black itself needs Python 3.10+ to run, but it can target output for Python 3.3 through 3.15 via --target-version.

Q: What does compiled: yes in --version mean? You installed a mypyc-compiled build, which runs faster. Pure-Python builds (compiled: no) behave identically, just slower.