How to Configure Ruff Formatter: quote-style, indent-style, and line-length Settings
I recently switched from Black to Ruff for formatting my Python code. While Ruff’s defaults match Black almost perfectly, I needed to understand how to customize the formatter settings to fit different project requirements.
The Problem: Understanding Ruff’s Format Configuration
When I first started using Ruff, I assumed it was just a linter. Then I discovered Ruff also includes a formatter that can replace Black entirely. But I was confused about where to configure formatting options like quote style and indentation.
The answer is simple: Ruff format settings go in pyproject.toml under the [tool.ruff.format] section. Let me show you how this works.
Ruff Format Default Settings
Ruff intentionally mirrors Black’s defaults, which makes migration painless:
line-length: 88 # Same as Blackindent-width: 4 spaces # Standard Python indentationquote-style: "double" # Black uses double quotesThese defaults mean most projects can switch from Black to Ruff with zero configuration. I tried it on several projects and the formatted output was identical.
Basic Format Configuration
The minimal configuration for Ruff format lives in pyproject.toml:
[tool.ruff]line-length = 88indent-width = 4
[tool.ruff.format]quote-style = "double"indent-style = "space"skip-magic-trailing-comma = falseline-ending = "auto"The [tool.ruff] section controls the top-level settings that apply to both linting and formatting. The [tool.ruff.format] section contains formatter-specific options.
Understanding Each Format Setting
quote-style
This setting determines which quotes Ruff uses for strings:
[tool.ruff.format]quote-style = "double" # Uses " for strings[tool.ruff.format]quote-style = "single" # Uses ' for stringsI prefer single quotes for strings (a habit from JavaScript), so I set quote-style = "single" in my projects. Ruff automatically handles quotes inside strings, escaping them when necessary.
indent-style
Controls whether Ruff uses spaces or tabs for indentation:
[tool.ruff.format]indent-style = "space"[tool.ruff.format]indent-style = "tab"Stick with spaces unless your team specifically requires tabs. Python’s PEP 8 recommends spaces, and most formatters use them by default.
skip-magic-trailing-comma
Black introduced the “magic trailing comma” concept. When you put a trailing comma after the last item in a list, dictionary, or function call, Black keeps those items on separate lines:
# With trailing comma - Black preserves multi-line formatitems = [ "first", "second", "third", # <- This comma is magic]
# Without trailing comma - Black may collapse to single lineitems = ["first", "second", "third"]By default, Ruff respects this behavior:
[tool.ruff.format]skip-magic-trailing-comma = false # Respects trailing commas (default)Set skip-magic-trailing-comma = true to ignore trailing commas and let Ruff decide the formatting purely based on line length.
line-ending
Controls line endings (LF vs CRLF):
[tool.ruff.format]line-ending = "auto" # Detects from file (default)# Or explicitly:# line-ending = "lf" # Unix/Linux/macOS# line-ending = "crlf" # WindowsUse "auto" unless you have specific requirements. Git can handle line ending normalization via .gitattributes.
Advanced Format Settings
docstring-code-format
This is my favorite Ruff formatter feature. It formats code inside docstrings:
[tool.ruff.format]docstring-code-format = truedocstring-code-line-length = "dynamic"When enabled, Ruff formats code examples in docstrings:
def calculate_sum(numbers): """ Calculate the sum of a list of numbers.
Example: >>> numbers = [1, 2, 3, 4, 5] >>> result = calculate_sum(numbers) >>> print(result) 15
Args: numbers: A list of numbers to sum.
Returns: The sum of all numbers. """ return sum(numbers)The docstring-code-line-length option can be:
"dynamic": Use the docstring’s indentation as the line length limit- A specific number like
60: Use that as the line length limit
exclude Files from Formatting
You can exclude specific files or patterns from formatting:
[tool.ruff.format]exclude = [ "migrations/*", "generated/*", "legacy_code.py",]This is useful for generated code or files from legacy systems that you don’t want to reformat.
A Complete Example Configuration
Here’s a configuration I use for new projects:
[tool.ruff]target-version = "py311"line-length = 100indent-width = 4
[tool.ruff.lint]select = ["E", "F", "I", "N", "W", "D"]ignore = ["D100", "D104"]
[tool.ruff.format]quote-style = "single"indent-style = "space"docstring-code-format = truedocstring-code-line-length = "dynamic"
[tool.ruff.lint.pydocstyle]convention = "google"This configuration uses:
- 100 character line length (slightly longer than default)
- Single quotes for strings
- Google-style docstrings
- Automatic docstring code formatting
Common Mistakes to Avoid
Mismatch Between Format and Lint Settings
If you change line-length in [tool.ruff], both the formatter and linter use it. But if you only change it in the formatter, the linter still uses 88:
[tool.ruff]# line-length not set, defaults to 88
[tool.ruff.format]# This only affects formatting, not linting!# E501 (line too long) will still use 88line-length = 100 # This won't work![tool.ruff]line-length = 100 # This applies to both linter and formatter
[tool.ruff.format]# No need to set line-length hereEnabling docstring-code-line-length Without docstring-code-format
[tool.ruff.format]# docstring-code-format is false by default!docstring-code-line-length = "dynamic" # This has no effect[tool.ruff.format]docstring-code-format = truedocstring-code-line-length = "dynamic" # Now this worksExcluding Files from Formatting But Not Linting
If you exclude a file from formatting, it still gets linted:
[tool.ruff.format]exclude = ["generated/*"] # Not formatted
[tool.ruff.lint]# generated/* is still linted! Add exclude here too if neededexclude = ["generated/*"]Related Knowledge: Ruff vs Black
Ruff’s formatter is designed to be a drop-in replacement for Black. The key differences are:
- Speed: Ruff is written in Rust and can be 100x faster than Black
- Integration: Ruff combines linting and formatting in one tool
- Configuration: Ruff uses
pyproject.tomlexclusively; Black supports multiple config files
The formatting output should be nearly identical to Black for most code. There are minor edge cases where they differ, but Ruff documents these clearly in their compatibility guide.
Running Ruff Format
After configuring your settings, run the formatter:
# Check formatting without changing filesruff format --check .
# Format files in placeruff format .
# Format specific filesruff format src/I recommend running ruff format --check in your CI pipeline to catch formatting issues before they reach the main branch.
In this post, I explained how to configure Ruff’s formatter settings including quote-style, indent-style, and line-length. I covered the default settings that match Black, explained each format option with examples, and highlighted common configuration mistakes. I also shared a complete example configuration and showed how to run the formatter from the command line.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments