Skip to content

How to Configure Ruff Linting Rules: select, ignore, and fixable Settings

I was working on a Python project recently and wanted to set up better linting. I’d heard about Ruff being super fast, so I gave it a try. But when I first ran it, I got confused by all the different rule codes and configuration options. What does “E501” mean? Why doesn’t Ruff complain about line length by default? Let me show you how I figured out Ruff’s lint configuration.

The Problem: Understanding Ruff’s Rule System

When I first used Ruff, I noticed something strange. Running ruff check on my code didn’t complain about long lines, but Flake8 did. What’s going on?

The answer is simple: Ruff doesn’t enable all the same rules as Flake8 by default.

This is actually a good thing. Ruff takes a conservative approach - it only enables rules that catch definite errors by default. Things like syntax errors, undefined variables, and import issues. This means you won’t get overwhelmed with warnings when you first start using Ruff.

But sooner or later, you’ll want to customize which rules Ruff checks. That’s where the select, ignore, and fixable settings come in.

The Three Key Settings

Ruff’s lint configuration revolves around three main settings:

1. select - Enable Rules

The select setting tells Ruff which rule categories or specific rules to enable. By default, Ruff uses:

pyproject.toml
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]

This enables:

  • E4 - pycodestyle indentation errors
  • E7 - pycodestyle statement errors (like using == instead of is)
  • E9 - pycodestyle runtime errors (like syntax errors)
  • F - Pyflakes errors (like undefined names or unused imports)

Notice what’s NOT included by default:

  • W - pycodestyle warnings (including E501 line-length violations)
  • C901 - McCabe complexity checks

This differs from Flake8, which enables more rules out of the box. If you’re migrating from Flake8, you might want to add more rules.

2. ignore - Disable Rules

The ignore setting lets you disable specific rules. For example, if you don’t want to enforce line-length limits:

pyproject.toml
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "W"]
ignore = ["E501"]

This enables all the default rules plus pycodestyle warnings, but ignores E501 (line too long).

3. fixable and unfixable - Control Auto-fixing

Ruff can automatically fix some violations when you run ruff check --fix. The fixable and unfixable settings control which rules can be auto-fixed.

By default, fixable = ["ALL"], meaning Ruff will fix all violations that have a fix available. But you might want to prevent certain fixes:

pyproject.toml
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "B"]
unfixable = ["B"]

This prevents Ruff from auto-fixing bugbear (B) violations. Why would you want this? Some fixes might change behavior or require manual review.

Understanding Rule Codes

Ruff uses a code system where each letter represents a category:

CodeCategoryDescription
FPyflakesUndefined names, unused imports
Epycodestyle ErrorStyle errors
Wpycodestyle WarningStyle warnings
CComplexityMcCabe complexity, cognitive complexity
Bflake8-bugbearCommon bugs and design problems
IisortImport sorting
Npep8-namingNaming conventions
UPpyupgradeModernize Python syntax
ANNflake8-annotationsType annotation checks
Sflake8-banditSecurity issues

You can see all available rules on the Ruff Rules page.

Common Configuration Examples

Example 1: Enable All Rules

I tried this when I wanted maximum checking:

pyproject.toml
[tool.ruff.lint]
select = ["ALL"]
ignore = [
"D", # Disable all docstring rules
"ANN", # Disable type annotation requirements
"E501", # Disable line-length checks
]

Using select = ["ALL"] enables every rule Ruff supports. Then I use ignore to disable the ones I don’t want.

Warning: This will produce A LOT of warnings on existing code. Start with a smaller selection and add rules gradually.

Example 2: Minimal Configuration with Bugbear

For new projects, I like to add bugbear rules:

pyproject.toml
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "B", "I"]
ignore = ["E501"]

This gives me:

  • Default error checking
  • Bugbear (B) for common bug patterns
  • Import sorting (I)

Example 3: Flake8 Compatibility

If you’re migrating from Flake8, this configuration is similar:

pyproject.toml
[tool.ruff.lint]
select = ["E", "F", "W", "C901"]
ignore = ["E501"]

Note: Ruff doesn’t enable W rules by default, so I add them explicitly.

Per-File Ignores

Sometimes you need to ignore certain rules in specific files. For example, __init__.py files often have imports at the bottom:

pyproject.toml
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["E402"] # Allow module-level imports after other code
"**/{tests,docs,tools}/*" = ["E402", "S101"] # Tests can use asserts

The key is the file pattern, and the value is a list of rule codes to ignore.

I use this for test files that intentionally use assert statements (S101) or have imports in unusual places.

The Difference Between select and extend-select

There’s also an extend-select option that adds to the default selection instead of replacing it:

pyproject.toml
[tool.ruff.lint]
# This REPLACES the default selection
select = ["B"]
# This ADDS to the default selection
extend-select = ["B"]

Use extend-select when you want to keep the defaults and add more rules.

A Practical Configuration

Here’s a configuration I use for my Python projects:

pyproject.toml
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # Pyflakes
"I", # isort
"B", # flake8-bugbear
"UP", # pyupgrade
]
ignore = [
"E501", # line too long (let the formatter handle it)
"B008", # do not perform function calls in argument defaults
]
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["E402"]
"**/tests/*" = ["S101"]

This configuration:

  1. Enables common error checks
  2. Sorts imports automatically
  3. Catches bug patterns
  4. Suggests modern Python syntax
  5. Ignores line length (let the formatter handle it)
  6. Allows test assertions

When you run ruff check --fix, Ruff applies fixes in a specific order. Understanding this helps you write better configurations.

Ruff categorizes fixes into:

  1. Safe fixes - Apply automatically with --fix
  2. Unsafe fixes - Require --unsafe-fixes flag
  3. Display-only fixes - Show suggestions but never auto-apply

You can check if a rule is fixable by looking at its documentation page. For example, E501 (line-too-long) is NOT fixable because shortening lines requires human judgment.

Summary

In this post, I explained how Ruff’s lint configuration works. I covered the three main settings: select for enabling rules, ignore for disabling rules, and fixable/unfixable for controlling auto-fixing. I showed you practical examples including how to enable all rules, migrate from Flake8, and use per-file ignores. The key takeaway is that Ruff starts conservative with defaults but gives you powerful customization options through pyproject.toml.

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