Last modified: Oct 14, 2026

Configure isort with Black

isort sorts imports. Black formats everything else. Both tools rewrite the same Python file, and without proper setup they undo each other's work.

The result is frustrating. You run isort, then Black, and the imports change back. You run Black, then isort, and the line breaks shift again. Nothing ever settles.

This guide fixes that problem for good. You will learn why the conflict happens, how the Black profile solves it, and how to wire both tools into your project so they agree every time.

Why isort and Black Conflict

Both tools care about the same lines of code. Import statements are just regular Python lines, so Black has opinions about them.

Black prefers one style for multi-line imports. It uses parentheses, trailing commas, and a specific line length. isort has its own default style, which is different.

When the two styles disagree, each tool sees the other's output as wrong. isort rewrites the import block in its format. Black rewrites it back in its format. The loop never ends.

The good news is that this is a solved problem. The isort project ships a built-in compatibility profile designed specifically for Black.

If you are new to isort, it helps to first understand the basics of how to sort Python imports automatically with isort. That gives you the foundation for the configuration below.

The One-Line Fix: The Black Profile

The easiest solution is a single configuration option. Set the isort profile to black and the conflicts disappear.

 [tool.isort] profile = "black" 

That is it. This one line changes several isort settings at once.

It switches the multi-line output mode to vertical hanging indent. It enables trailing commas. It sets the line length to 88. It enables parentheses for wrapped imports. It also stops isort from adding a newline before comments inside imports.

All of these are the exact choices Black expects. With the profile active, both tools produce identical output.

If you have not installed isort yet, follow this guide on how to install isort in Python first. Then return here to configure it.

What the Black Profile Actually Sets

Understanding the underlying options helps when you need to customize further. Here is what the profile expands to.

 [settings] multi_line_output = 3 include_trailing_comma = True force_grid_wrap = 0 use_parentheses = True ensure_newline_before_comments = True line_length = 88 

The multi_line_output value of 3 means vertical hanging indent. This is the style Black produces when an import is too long for one line.

The include_trailing_comma option adds a comma after the last item. Black does this too, and it keeps future diffs clean.

The force_grid_wrap option is set to zero, which prevents isort from wrapping short imports unnecessarily.

The use_parentheses option wraps imports in parentheses instead of using backslashes. Black never emits backslash continuations.

You do not need to memorize these values. The profile sets them for you. But knowing them helps when you want to override one specific behavior.

Full pyproject.toml Example

Most modern projects keep all tool config in one file. Here is a realistic pyproject.toml with both isort and Black configured side by side.

 [tool.isort] profile = "black" line_length = 88 known_first_party = ["myapp"] src_paths = ["src", "tests"] skip = ["migrations", ".venv", "build"] combine_as_imports = true [tool.black] line_length = 88 target-version = ["py311"] 

Notice that line_length is set to 88 in both sections. That number must match. If isort wraps imports at 100 and Black wraps code at 88, you get inconsistent files.

The known_first_party option tells isort which packages belong to your own project. Without it, your local modules can end up in the third-party block.

The src_paths option tells isort where your code lives. This improves import resolution in projects that use a src layout.

Using .isort.cfg Instead

Some teams prefer a dedicated config file. The .isort.cfg format still works and is fully supported.

 [settings] profile = black line_length = 88 known_first_party = myapp src_paths = src,tests 

The behavior is identical. isort reads pyproject.toml, .isort.cfg, setup.cfg, and tox.ini in a defined order.

Pick one file and stick with it. Mixing formats across a repository leads to confusion about which settings are actually active.

Running Both Tools in the Right Order

Configuration solves the conflict. Order solves the workflow. Always run isort before Black.

 isort . black . 

isort rearranges the import blocks first. Black then formats the rest of the file, including any long import lines that isort already shaped.

If you reverse the order, Black formats the imports in its style and isort may still want to regroup them. The final result is usually fine, but the intermediate state causes noisy diffs.

You can also call both tools from Python. This is useful inside build scripts or code generators.

 import isort import black source = """ import sys import requests from myapp import models import os """ # Step 1: sort imports first sorted_source = isort.code(source, profile="black") # Step 2: format the full source with Black formatted = black.format_str(sorted_source, mode=black.Mode()) print(formatted) 

The output shows both steps applied cleanly.

 import os import sys import requests from myapp import models 

The isort.code() method handles import ordering. The black.format_str() method handles everything else. Running them in this sequence guarantees agreement.

Automating with Pre-commit

Manual runs are easy to forget. Pre-commit hooks run both tools before every commit, in the correct order.

 repos: - repo: https://github.com/PyCQA/isort rev: 6.0.1 hooks: - id: isort args: ["--profile", "black"] - repo: https://github.com/psf/black rev: 24.10.0 hooks: - id: black 

Order matters inside this file too. The isort hook is listed first, so it runs first.

Install the hooks once with a single command.

 pre-commit install 

From now on, every commit triggers both tools. If a file needs changes, the tools fix it and the commit is blocked once so you can review the result.

The --profile black argument is technically redundant when your config file already sets it. Keeping it in the hook makes the intent explicit and protects against missing config.

Enforcing Both Tools in CI

Pre-commit protects your machine. CI protects the shared branch. You want both.

 name: Format Check on: [push, pull_request] jobs: format: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - run: pip install isort black - run: isort . --check --diff - run: black . --check --diff 

Both commands use the check flag. They exit with a non-zero code if any file is not formatted, which fails the job.

The diff flag prints exactly which lines need fixing. Contributors see the problem immediately without guessing.

If your project also runs data pipelines, consistent formatting pays off across the whole codebase. Teams that schedule Python tasks with Airflow often maintain dozens of DAG files, and a shared style makes those files far easier to scan during an incident.

Checking a File from Python

Sometimes you need a programmatic check instead of a shell command. The isort API supports that directly.

 import isort # Returns True when imports are already sorted result = isort.check_code("import os\nimport sys\n", show_diff=True) print(result) 

The output confirms the file is clean.

 True 

The isort.check_code() method returns a boolean and never writes to disk. It is ideal inside test suites that verify formatting rules.

You can also rewrite a file directly with the Python API.

 import isort # Sort imports in a file and save the change isort.file("src/app.py") 

The isort.file() method applies the change in place. Use it when generating files so the output is always sorted.

Common Configuration Mistakes

Line length mismatch. If isort uses 79 and Black uses 88, the tools will keep fighting. Set both to the same value.

Missing the profile in CI. If your config file is not committed, CI falls back to defaults and reports false failures. Always commit the config.

Running Black before isort. This produces extra churn. Order is import sorting first, formatting second.

Multiple config files. Having both pyproject.toml and .isort.cfg with different values causes unpredictable results. Keep one.

Outdated isort. The Black profile has improved over time. Old versions may miss options like ensure_newline_before_comments. Upgrade to the latest release.

Skipping the profile flag in hooks. Even with a config file present, adding --profile black to hook arguments prevents surprises when the config is not found.

Verifying the Setup

Once everything is configured, run a quick sanity check. Create a test file with deliberately messy imports and long lines.

 import sys import requests import os from mypackage.subpackage.module import some_function_with_a_very_long_name_here 

Run both tools and inspect the result.

 isort test_file.py --profile black black test_file.py cat test_file.py 

The output should show grouped imports and a wrapped long line with parentheses and a trailing comma.

 import os import sys import requests from mypackage.subpackage.module import ( some_function_with_a_very_long_name_here, ) 

If your file looks like this, the setup is correct. Both tools agree, and the format is stable.

Conclusion

Configuring isort with Black takes one line of configuration. Set profile = "black" and the conflict is gone.

From there, the work is about workflow. Match your line lengths. Run isort before Black. Add both to pre-commit. Enforce both in CI.

Do those four things and your formatting stops being a topic of discussion. Files stay consistent, diffs stay small, and code reviews focus on logic instead of style.

Set it up once. Let the tools handle the rest.