Ruff 0.16 turns on 354 more rules by default — brace your CI

4 min read 1 source clear_take
├── "The new defaults are a deliberate, welcome end to Ruff's 'polite' era — Astral is now shipping its considered opinion on Python code quality"
│  ├── Astral (astral.sh blog) → read

Astral frames the 7x expansion as intentional and overdue: after two years of shipping rule families behind opt-in flags, they're now asserting that pyflakes, pycodestyle, isort, pyupgrade, bugbear, comprehensions, simplify, and pie represent the sensible baseline for a modern Python project. The release notes explicitly tell users to either accept the new defaults or pin `select` to restore old behavior — signaling this is a philosophical shift, not an accident.

│  └── top10.dev editorial (top10.dev) → read below

The editorial argues that speed alone never made Ruff opinionated — what ships in the default `select` set does. Version 0.16 marks Ruff's transition from a polite flake8 drop-in to an assertive code reviewer that stakes out a position on what good Python looks like, which is a natural move now that Ruff has won the linter war on performance.

└── "Turning on 354 new rules by default is a disruptive breaking change that will flood existing codebases with diagnostics"
  ├── top10.dev editorial (top10.dev) → read below

The editorial highlights that any project running `ruff check` without pinning `select` in pyproject.toml will suddenly surface hundreds to thousands of new diagnostics on a routine upgrade. Rules previously considered too aggressive for zero-config — like B008 (mutable default arguments) and SIM108 (ternary preference) — now fire out of the box, forcing every Ruff user to make an explicit decision about their linter posture.

  └── @vismit2000 (Hacker News, 144 pts) → view

By submitting the release with the headline emphasis on '413 default rules up from 59,' the submitter frames the story around the sheer scale of the jump rather than the individual rule quality — suggesting the magnitude of the change is itself the news, and implicitly a warning to teams who upgrade without reading the notes.

What happened

Astral shipped Ruff v0.16.0 and quietly redrew the line between "a linter" and "an opinionated code reviewer." The default rule set jumped from 59 rules to 413 — a 7x increase that pulls in most of the linter families Ruff has been shipping behind opt-in `select` flags for the last two years.

The new defaults include the full `pyflakes` (F), `pycodestyle` (E, W), `isort` (I), `pyupgrade` (UP), `flake8-bugbear` (B), `flake8-comprehensions` (C4), `flake8-simplify` (SIM), and `flake8-pie` (PIE) families, among others. Rules previously considered too aggressive or too opinionated for a zero-config experience — like `B008` (mutable default arguments in function signatures) or `SIM108` (use ternary instead of if/else assignment) — now fire on a fresh `ruff check .` with no config file.

For a project that previously ran `ruff check` and got a clean bill of health, upgrading to 0.16.0 without pinning `select` in `pyproject.toml` will surface hundreds to thousands of new diagnostics on first run. Astral is explicit about this in the release notes: the change is intentional, and the migration path is either accept the new defaults, or explicitly pin `select = ["F"]` (or whatever subset you were actually running) to restore the old behavior.

Why it matters

Ruff has spent two years winning the Python linter war on speed — 10-100x faster than flake8, written in Rust, drop-in compatible with the flake8 plugin ecosystem. But speed alone doesn't make a linter *opinionated*. What ships in the default `select` set does. And until 0.16, Ruff's defaults were deliberately conservative: essentially just pyflakes (F) plus a handful of pycodestyle errors. That was the polite way to enter a market dominated by flake8, black, isort, and a dozen bespoke pre-commit configs.

Version 0.16 ends the politeness era. Astral is now telling the ecosystem that if you don't have a reason to disagree, these 413 rules represent their considered opinion on what Python code should look like in 2026. That's a big claim from a tool that now ships in CI for a substantial fraction of Python projects on GitHub — including CPython itself, pandas, FastAPI, and Airflow.

The rule expansion is not random. It maps closely to the rules that most well-maintained Python projects already enable manually. If you look at the `pyproject.toml` of any large open-source Python codebase, you'll typically find a `select = ["E", "F", "W", "I", "B", "UP", "SIM", "C4"]` block or something very similar. Astral has essentially audited what the ecosystem was already doing and made it the default. That's a defensible move — but it means the tool's behavior now depends on decisions you didn't make.

Community reaction on HN and the astral-sh/ruff issue tracker split predictably. One camp welcomes the change: fewer projects with under-configured linters, fewer bikeshed arguments about `select` blocks in PR reviews, a more consistent baseline across the ecosystem. The other camp — largely maintainers of large legacy codebases — is bracing for the CI carnage. A rule like `SIM108` (collapse if/else into ternary) can fire hundreds of times in a codebase that predates walrus operators and type hints, and none of those violations represent actual bugs.

There's also a subtler concern about linter drift as a supply-chain issue. If your CI runs `pip install ruff` without a pin, or pins only the major version, a Ruff release can now change what "passing lint" means overnight. That's fine when the delta is one new rule; it's less fine when the delta is 354 rules, some of which will flag idioms that were considered best practice five years ago.

What this means for your stack

Three concrete actions, in order of urgency.

First, pin Ruff exactly in your lockfile and pin your `select` block in `pyproject.toml`. If you were relying on Ruff's defaults, add `select = ["F"]` (or whatever subset matches your prior behavior — check the 0.15 defaults in the changelog) before you upgrade. This turns the migration from a surprise into a decision. Anyone running `ruff` in CI without a pinned config is now one `dependabot` PR away from a red build with 2,000 new warnings.

Second, when you do adopt the new defaults, do it in a dedicated PR with `ruff check --fix --unsafe-fixes` and review the diff. Roughly 60-70% of the new rules have auto-fixes; the rest need human judgment. Rules like `B008` (mutable defaults) are almost always real bugs worth fixing. Rules like `SIM102` (nested if-statements) are often style preferences that hurt readability when applied mechanically. Use `# noqa: SIM102` liberally on the ones that don't earn their keep in your codebase, or disable them wholesale in `pyproject.toml`.

Third, if you maintain a library, update your `pyproject.toml` before your users' CI catches fire. Downstream users who inherit your Ruff config via a shared preset (increasingly common with tools like `hatch` and `uv`) will hit the new defaults on their next update. A one-line `select` pin protects them.

For greenfield projects, the new defaults are genuinely a better starting point than what most teams cobble together. The rule set represents years of accumulated wisdom from the flake8 plugin ecosystem, distilled and de-duplicated. You'll get better code out of the box than a hand-rolled config from a junior engineer copying snippets off Stack Overflow.

Looking ahead

Astral's endgame with Ruff has always been to make Python tooling look more like Go tooling — one binary, one config, sensible defaults, no debate. Version 0.16 is the moment the "sensible defaults" part gets real. Expect the next few releases to keep expanding the default set (the `PL` Pylint rules are the obvious next battleground) and expect the community's arguments about what belongs in defaults to get sharper as the stakes rise. If you've been treating Ruff as a faster flake8, it's time to start treating it as a code style authority with an opinion — and to decide, deliberately, how much of that opinion you want to accept.

Hacker News 326 pts 212 comments

Ruff v0.16.0 – Significant new updates – 413 default rules up from 59

→ read on Hacker News

// share this

// get daily digest

Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.