Skip to content

pyproject.toml vs ruff.toml: Which Ruff Config File Should You Use?

I recently started using Ruff to lint and format my Python code, but I got confused by the configuration options. Should I use pyproject.toml or ruff.toml? Which one is better? Let me share what I learned.

The Problem

I installed Ruff in my Python project and wanted to configure it to match my coding style. I noticed that Ruff supports multiple configuration files, but I wasn’t sure which one to choose. The documentation mentioned pyproject.toml, ruff.toml, and even .ruff.toml. What’s the difference?

The Direct Answer

Ruff supports three configuration files:

  1. pyproject.toml - Requires a [tool.ruff] section header
  2. ruff.toml - Omits the [tool.ruff] header and tool.ruff prefix
  3. .ruff.toml - Same syntax as ruff.toml, but with higher precedence

All three files implement the same schema. The only difference is the syntax. If multiple config files exist in the same directory, Ruff follows this precedence order:

.ruff.toml > ruff.toml > pyproject.toml

This means .ruff.toml takes the highest priority, followed by ruff.toml, and finally pyproject.toml.

Code Examples

Let me show you how each file looks.

pyproject.toml

When using pyproject.toml, you must include the [tool.ruff] section header. Ruff ignores pyproject.toml files that lack this section.

pyproject.toml
[tool.ruff]
line-length = 88
target-version = "py39"
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]
ignore = ["E501"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"

Notice how every Ruff setting starts with [tool.ruff] or [tool.ruff.lint] or [tool.ruff.format].

ruff.toml

The ruff.toml file uses a simpler syntax. You can omit the [tool.ruff] header and the tool.ruff prefix.

ruff.toml
line-length = 88
target-version = "py39"
[lint]
select = ["E4", "E7", "E9", "F"]
ignore = ["E501"]
[format]
quote-style = "double"
indent-style = "space"

Compare this to pyproject.toml. The [tool.ruff.lint] becomes just [lint], and [tool.ruff.format] becomes [format].

.ruff.toml

The .ruff.toml file uses the same syntax as ruff.toml. The only difference is the filename and precedence.

.ruff.toml
line-length = 100
target-version = "py39"
[lint]
select = ["E4", "E7", "E9", "F"]
ignore = ["E501"]
[format]
quote-style = "single"

Since .ruff.toml has the highest precedence, it will override settings from ruff.toml and pyproject.toml if they exist in the same directory.

Why Would You Choose One Over Another?

Now you might wonder: which one should I use?

Choose pyproject.toml if:

  • You already have a pyproject.toml in your project (for packaging, dependencies, etc.)
  • You want all tool configurations in one place (Black, MyPy, Pytest, etc. all support pyproject.toml)
  • You prefer the standard Python project layout

This is my preferred approach because I can keep all my tool configurations in one file. For example:

pyproject.toml with multiple tool configs
[project]
name = "my-project"
version = "0.1.0"
[tool.ruff]
line-length = 88
[tool.black]
line-length = 88
[tool.mypy]
python_version = "3.9"
warn_return_any = true

Choose ruff.toml or .ruff.toml if:

  • You don’t have a pyproject.toml (maybe a simple script project)
  • You want Ruff-specific settings in a separate file
  • You need to override project-level settings locally (use .ruff.toml for this)

The ruff.toml file is cleaner because you don’t need to type [tool.ruff] everywhere.

Common Mistakes to Avoid

I made these mistakes when I started, so let me share them to save you time.

Mistake 1: Missing the [tool.ruff] Header in pyproject.toml

This is the most common mistake. If you add Ruff settings to pyproject.toml without the [tool.ruff] header, Ruff will ignore them completely.

WRONG: Missing header - Ruff will ignore this
line-length = 88
[lint]
select = ["E4", "E7", "E9", "F"]
CORRECT: With proper header
[tool.ruff]
line-length = 88
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]

Mistake 2: Using Wrong Section Prefix in ruff.toml

In ruff.toml, you should NOT use the [tool.ruff.lint] format. It should be just [lint].

WRONG: Using pyproject.toml syntax in ruff.toml
[tool.ruff]
line-length = 88
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]
CORRECT: Proper ruff.toml syntax
line-length = 88
[lint]
select = ["E4", "E7", "E9", "F"]

Mistake 3: Creating Multiple Config Files Without Understanding Precedence

If you have both pyproject.toml and ruff.toml in the same directory, ruff.toml takes precedence. This can be confusing when you change settings in pyproject.toml but nothing happens.

Project structure with multiple config files:
├── pyproject.toml (line-length = 88)
├── ruff.toml (line-length = 100) # This wins!
└── src/
└── main.py

In this case, Ruff will use line-length = 100 from ruff.toml.

What is pyproject.toml?

pyproject.toml is the standard configuration file for Python projects, introduced in PEP 518. It specifies build system requirements and can contain configuration for various tools. Many tools support it: Black, MyPy, Pytest, Coverage.py, and of course, Ruff.

What is Ruff?

Ruff is an extremely fast Python linter and formatter written in Rust. It can replace multiple tools: Flake8, isort, pydocstyle, pyupgrade, and Black. It’s 10-100x faster than traditional Python linters.

How Does Ruff Find Config Files?

Ruff searches for configuration files in the following order:

  1. Explicitly specified via --config flag or RUFF_CONFIG environment variable
  2. .ruff.toml in the current directory
  3. ruff.toml in the current directory
  4. pyproject.toml in the current directory
  5. Parent directories (up to the project root)

Combining Multiple Configurations

Ruff supports extending configurations from other files using the extend option:

ruff.toml extending base config
extend = "../base-ruff.toml"
[lint]
select = ["E4", "E7", "E9", "F", "I"] # Added "I" for import sorting

This is useful for sharing common settings across multiple projects.

Summary

In this post, I explained the three configuration files that Ruff supports: pyproject.toml, ruff.toml, and .ruff.toml. All three implement the same schema, but with slightly different syntax. pyproject.toml requires the [tool.ruff] header, while ruff.toml and .ruff.toml use a cleaner syntax without the prefix. The precedence order is .ruff.toml > ruff.toml > pyproject.toml. I recommend using pyproject.toml if you already have one in your project, as it keeps all tool configurations in one place.

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