Open-source project
psf/black avatar
psf/black

Black: whole-file rewrites, an AST check you can switch off, and a config file you should not copy

GitHub describes it as The uncompromising Python code formatter. The repository metadata lists Python as its primary language. The metadata lists the MIT license. This article stays within the project description and details documented in the GitHub repository README.

41,858 stars2,899 forksPythonMIT

At a glance

What is it?
The uncompromising Python code formatter, for teams that want one layout across every repository and are willing to hand over control of their own formatting. It rewrites whole files in place, ignores how you had already formatted them, offers almost no style options, and ships a pyproject.toml that contradicts its own advice about configuring nothing.
Who is it for?
Use it when a single layout across every repository is worth more than the local formatting habits your team has, and when you are willing to review one large diff on the first run. Do not reach for it to fix one file, because it has no partial mode and no way to preserve a region you formatted by hand.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

It rewrites the entire file and ignores whatever formatting you had

Two sentences define the blast radius. Black reformats entire files in place, and it does not take previous formatting into account, with the Pragmatism section named as the place where the exceptions live. There is no partial mode, no region to protect, and no per-file opt-out other than the exclude patterns in the configuration file. The entry point takes a path and nothing else, so scoping is a configuration decision rather than a command line one.

sh
black {source_file_or_directory}

If running it as a script does not work, there is a package form, which is the fallback worth remembering when a wrapper script or a constrained environment gets in the way.

sh
python -m black {source_file_or_directory}

The consequence of all this is concentrated in one moment, the first run. On a repository that has been hand-formatted for years, that run produces a diff in which almost every line changed and nobody read any of it, and the review you would normally give a large change is exactly the review this one cannot get. After that first pass the cost drops sharply, because the project is stable and says you should not expect large formatting changes in the future. Budget for the first diff as its own piece of work.

The AST equivalence check is the slow part, and --fast removes it

As a safety measure which slows down processing, Black checks that the reformatted code still produces a valid AST that is effectively equivalent to the original. That check is the only guard between a formatter and a semantic change, and it is also the part that costs time on a large tree. Passing `--fast` skips it. The trade is direct: on a monorepo, `--fast` is often the difference between a pre-commit hook developers tolerate and one they route around with `--no-verify`. Note the wording of the guarantee, that the AST is effectively equivalent rather than identical, and that the details sit in a Pragmatism section that the page explicitly links, so the boundary of what the check permits is documented rather than implied. The reasonable order is to run the first pass with the check on, learn where it complains, and only then decide whether speed is worth giving the guarantee up on subsequent runs.

The shipped pyproject.toml contradicts the advice to configure nothing

The configuration section answers its own question with a pro-tip. If you are asking yourself whether you need to configure anything, the answer given is no, because Black is all about sensible defaults and applying them will have your code in compliance with many other Black formatted projects. Now look at what this repository's own `pyproject.toml` contains.

toml
[tool.black]
line-length = 88
target-version = ["py310"]
include = '\.pyi?$'
extend-exclude = '''
/(
    # The following are specific to Black, you probably don't want those.
    tests/data/
    | profiling/
)
'''
unstable = true

The last line is the important one. A comment states that Black uses the unstable style to format itself, that you should keep this off if you want bug-free formatting, and that stable formatting across releases also requires keeping `preview = true` off, which this flag implies. So the project's own configuration is a deliberate exception, not a template. Copy the file from the documentation, not from this one.

Exclude patterns are regular expressions, not globs, and the quoting is load bearing

The config file opens with a warning that is easy to skim past. You have to use single-quoted strings in TOML for regular expressions. It is the equivalent of r-strings in Python. Multiline strings are treated as verbose regular expressions by Black. Use `[ ]` to denote a significant space character. Each of those four sentences prevents a specific silent failure. A double-quoted pattern picks up escape processing that you did not intend. A pattern written as a glob will match almost nothing, and because excludes that match nothing simply have no effect, you get no error, you just get files reformatted that you thought were protected. And a meaningful space written as a literal space instead of `[ ]` can disappear inside verbose mode, where whitespace is not read the way it looks. The `--include` and `--exclude`, `--force-exclude`, and `--extend-exclude` options are named as the main reason to have a config file at all, which tells you how much weight these patterns carry.

The only style number is 88, and the rest of the style is not negotiable

Style configuration options are deliberately limited and rarely added. That sentence is the whole configuration philosophy, and the repository's config shows what survives the filter: a line length, a target version, an include pattern, and excludes. Everything else about layout is not a knob. Black is described as a PEP 8 compliant opinionated formatter, and those two words work together, since compliance is the floor and the formatter then makes choices of its own where the standard does not settle the question. The consequence for a team is that there is no supported middle path. You either accept the style, which is the point, or you keep your own formatter. What you can adjust is line-length, the Python versions you target, and which files are in scope at all. If your objection is about a specific construct rather than about width, changing configuration will not address it.

main moved in September, the newest release is from May

The last push to the default branch `main` is dated 2026-09-28. The newest listed release is 26.5.1, published 2026-05-18, ahead of 26.5.0 on 2026-05-16 and 26.3.1 on 2026-03-12. Those are two different clocks, and knowing which one you are on matters when a formatting diff appears. Anyone tracking `main` is running code that has not shipped in a tagged release, and anyone pinning 26.5.1 is four months behind the branch. The root of the repository carries `CHANGES.md`, which is where the difference between those two states is recorded. The stability claim gives you a way to hold the project to something: it says that now that the project is stable you should not expect large formatting changes in the future, and that stylistic changes will mostly be responses to bug reports and support for new Python syntax. A reformat after an upgrade that is not a new syntax feature is a departure from that.

There are two style pages, and the second one reframes your issue

The style is split across two documents, and you are told both are worth a look: the current style, and the future style, which holds the planned changes. Changes to the style are bound by a stability policy, referenced separately. Reading only the current page is how you end up filing an issue for something already scheduled. The page even says so, twice, once for the code style and once for Pragmatism: refer to the document before submitting an issue, because what seems like a bug might be intended behaviour. The same warning applies to the exceptions the tool makes. Early versions were absolutist in some respects and took after the initial author, which was fine at the time because it kept the implementation simpler and there were not many users and not many edge cases reported. As a mature tool, Black does make some exceptions to rules it otherwise holds. So an inconsistency you can observe has a documented reason, in one of two named places, and that is the answer to why this one line is formatted differently from its neighbours.

Editorial conclusion

Use it when a single layout across every repository is worth more than the local formatting habits your team has, and when you are willing to review one large diff on the first run. Do not reach for it to fix one file, because it has no partial mode and no way to preserve a region you formatted by hand. Before you adopt it, read the future style page so you know which complaints are already scheduled, run it without --fast on the first pass so the AST equivalence check is actually doing something, and copy the config from the documentation rather than from Black's own pyproject.toml, which formats itself with the unstable style.

Frequently asked questions

What defines black in psf/black?

The documentation does not define the word. What the project defines is a formatter that reformats entire files in place, is a PEP 8 compliant opinionated formatter, and reads project-specific defaults for its command line options from a `pyproject.toml` file.

What is black if not a color in psf/black?

In this repository black is a Python code formatter, not a color. It installs with `pip install black`, requires Python 3.10+ to run, and formats a source file or directory given on the command line.

Why is black not considered a color, per psf/black?

psf/black does not discuss color theory. Its stated scope is formatting: by using it you agree to cede control over the minutiae of hand-formatting, and the stated goal is that blackened code looks the same regardless of the project you are reading.

Is white the absence of color or black, in psf/black?

Not a question this project answers. The closest thing to a color statement in its documentation is the reply `Any color you like.` to a request for a configurable color scheme, which is to say the formatter does not take a color option.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/psf-black.svg)](https://hysenlabs.com/projects/psf-black)