Summary: On July 23, Astral shipped Ruff v0.16.0, and for most projects the headline change needs only one sentence: once you upgrade, ruff check enforces 413 rules with zero configuration — seven times the 59 rules the previous version enabled by default. It is the closing move of Ruff’s long-running rule recategorization project (issue #1774), in which the team re-evaluated the opt-in rules one by one and promoted the ones that had proven stable and high-signal into the default set.
On July 23, Astral shipped Ruff v0.16.0, and for most projects the headline change needs only one sentence: once you upgrade, ruff check enforces 413 rules with zero configuration — seven times the 59 rules the previous version enabled by default. The official blog post says exactly that in its title: “Ruff now enables 413 rules by default, up from 59.”
A tool’s defaults amount to a statement of philosophy. Multiplying the default rule count by seven says Astral now treats strict-out-of-the-box as the baseline expectation for Python projects. Before you upgrade, it is worth seeing what moved and why.
What Changed: How 59 Default Rules Became 413
This is no impulsive rule dump. It is the closing move of Ruff’s long-running rule recategorization project (issue #1774), in which the team re-evaluated the opt-in rules one by one and promoted the ones that had proven stable and high-signal into the default set. The overall rule count has grown as well, from 708 at v0.1.0 to 968 today.
The nerve to switch so much on by default comes from speed: Ruff is written in Rust, and a scan with every rule enabled still outruns older tools running a handful of checks. When the cost of checking approaches zero, “turn everything on, disable case by case” is the rational strategy. For a sense of the scale, a default-on Ruff now covers categories many projects used to enable selectively — correctness checks, likely bugs, suspicious patterns — with no configuration at all. Projects that maintain a hand-curated enable-list may find most of it redundant, and brand-new projects get a sensible baseline from ruff check alone.
Eighteen Rules Left the Default Set
Subtraction happened too. Eighteen opinionated pycodestyle and pyflakes rules were dropped from the defaults, including E401 (multiple imports on one line), E711/E712 (comparisons to None and True), E731 (assignment of lambda), E741 (ambiguous variable names), and F403 (star imports). These have long been sources of style arguments; the release provides a config snippet so projects that want the old behavior can restore it.
The direction is unmistakable: defaults should be high-signal and low-controversy, with style preferences left to the user. That runs opposite to the “defaults keep getting looser” path many linters have taken — Ruff enables the error-like rules everywhere and lets the style rules yield. E711 and E712 are a useful illustration: comparing with is None is the safer form, but forcing that rewrite across a legacy codebase all at once is precisely the kind of change that belongs behind an explicit decision rather than a silent default.
Markdown Formatting and New Suppression Comments
v0.16 also ships two practical feature groups. First, Ruff can now format Python code blocks embedded in Markdown files, covering python, pyi, and pycon fenced blocks plus Quarto {python} blocks — example code in documentation finally gets the same formatting pass as the codebase itself.
Second, suppression syntax is now complete: new ruff: ignore comments (inline or on the preceding line) and ruff: file-ignore for whole files, sitting alongside the ruff: disable/ruff: enable pairs introduced in v0.15. All of them accept an optional reason, and a new --add-ignore flag generates them for you. Also worth noting: check and format --check output now shows fix diffs inline, format --check supports JSON and GitHub/GitLab annotation formats, and 12 rules graduated from preview to stable. For teams that keep runbooks, tutorials, or data docs in Markdown, the formatting change closes a real gap: examples in documentation used to sit outside the formatter’s reach and quietly drifted from house style.
One small breaking change: some JSON output fields (such as filename and location) can now be null, so anything parsing that output should be checked.
Upgrade Notes
Three practical steps. First, run ruff check locally after upgrading and look at the volume of new diagnostics before touching CI — a direct upgrade will likely surface a batch of new failures. Then decide rule by rule whether to adopt and fix, or restore the old defaults with the official config snippet. Second, pin the version, so a change in defaults becomes one reviewable, revertible commit instead of something that drifts in through a dependency. Third, if your project has many Python examples in documentation, the formatting scope just grew; it is a good moment to fold Markdown into the checked set. None of this changes what Ruff is for — it changes how much of it you get before writing any configuration, and the release notes mark every behavior change, which makes the upgrade path unusually legible.
