New in 2026: Master Python for AI, Data Science

ProgrammingPython

Ruff 0.15 + 2026 Style Guide — Modern Python Formatting Explained

2057

You are still running Black, isort, and flake8 as three separate tools. Each one has its own config file, its own update cycle, and its own 200ms startup time. There is a better setup — and it ships as a single 2MB Rust binary that runs 100x faster. Ruff 0.15 just shipped with the 2026 style guide. Here is what changed and how to migrate in under 30 minutes.

In this tutorial, you will learn to:

  • Understand what changed in Ruff 0.15 and the 2026 style guide
  • Compare Ruff formatter against Black in 2026 — speed, rule coverage, and compatibility
  • Migrate an existing Black + isort + flake8 project to Ruff-only
  • Set up Ruff in GitHub Actions CI in under 10 minutes
  • Configure Ruff with uv for a zero-config start in new projects

What Is Ruff and Why Does It Matter in 2026?

Ruff is a Python linter and formatter written in Rust by Astral — the same team behind uv. It replaces Black, isort, flake8, and dozens of their plugins with a single tool that runs 10 to 100 times faster. Ruff 0.15, released in February 2026, is the release that makes Ruff’s formatter a credible, full-time Black replacement for teams that want one tool instead of four.

Here is the core comparison in 2026:

ToolWhat it doesSpeed
RuffLinter + formatter + import sorter10–100x faster than Black
BlackFormatter onlyReference (slow in Python)
isortImport sorter onlyFast but separate tool
flake8Linter only (plus plugins)Slow, startup overhead

Prerequisites

You should be comfortable on the command line and have a Python project with an existing pyproject.toml. No prior experience with Ruff is needed — this is a ground-up guide. If you want a refresher on setting up Python tooling, see the Python libraries guide for the modern toolchain overview.

What Changed in Ruff 0.15: The 2026 Style Guide

1. Lambda Parameters Stay on One Line

The most celebrated change in Ruff 0.15 is how it handles long lambdas. Black would break long lambda parameters across multiple lines, which was widely considered its worst formatting decision. Ruff 0.15 keeps lambda parameters on the same line and parenthesizes the body if it needs to break — matching what most developers actually wanted:

# Black (2024 style) — breaks lambda awkwardly
result = (
    lambda x, y, z, w: x + y + z + w
)(1, 2, 3, 4)

# Ruff 0.15 / 2026 style — parameters stay on one line
result = (lambda x, y, z, w: (x + y + z + w))(
    1, 2, 3, 4
)

2. Improved Spacing Around Magic Literals

The 2026 style guide tightens formatting around type[None], type[int], and other special type literals. Ruff now formats these with consistent spacing that was inconsistent or unavailable in older Black versions:

# Ruff 0.15 — consistent spacing for magic literals
x: type[None]      # no extra space inside brackets
y: type[int | str]  # union types inside brackets formatted cleanly

3. Respect for Existing Line Lengths in Multi-Line Constructs

One of the longest-running complaints with Black was that it would reformat code in ways that created large diffs even when no meaningful changes were made. Ruff 0.15 is smarter about preserving existing line breaks in function calls, comprehensions, and other multi-line constructs — reducing noise in code review when you adopt it.

4. Ruff Ships as the Formatter Behind uv format

If you use uv, the uv format command runs Ruff 0.15 with the 2026 style guide by default. This means you do not need to install Ruff separately for new projects — it comes included in uv 0.10.0 and later. For teams standardizing on uv, the formatter is already there.

# uv format uses Ruff 0.15 under the hood — no separate Ruff install needed
uv format

# Check without modifying files
uv format --check

# Format specific paths
uv format src/**/*.py

Ruff vs Black in 2026: What Is Actually Different?

Ruff is not 100% identical to Black — it is 99% compatible with intentional deviations where Ruff’s maintainers believe the Black behavior was wrong. The official docs list known deviations. Key differences in practice:

AreaBlackRuff 0.15 (2026)
Lambda parameter formattingBreaks params across linesKeeps params on one line
Magic literal spacingInconsistentStandardized in 2026 style
Line-length changesOften reformats entire filesPreserves existing breaks where possible
Import sortingRequires isort pluginBuilt in, compatible with isort config
Rule extensibilityNone — formatter only800+ lint rules via plugins
SpeedReference Python speed10–100x faster

The lambda formatting change is the most impactful for daily use — it eliminates the most common complaint developers had with Black. If you use black --diff in CI today and see large diffs on lambda-containing files, Ruff 0.15 will produce cleaner output.

Rule of thumb: If you are starting a new project in 2026, use uv format (Ruff) directly. If you are migrating an existing Black project, set Ruff’s formatter.black compatibility mode to minimize diff noise during the transition.

Migrating from Black + isort + flake8 to Ruff

Step 1: Install Ruff

# Option 1: via uv (recommended)
uv tool install ruff

# Option 2: via pip
pip install ruff

# Option 3: standalone installer
curl -LsSf https://astral.sh/ruff/install.sh | sh

Step 2: Add Ruff Configuration to pyproject.toml

Add a [tool.ruff] section alongside your existing tool configs. Ruff can read your existing Black line-length and isort settings directly:

# pyproject.toml

[tool.ruff]
# Enable the formatter (replaces Black)
line-length = 88  # inherited from your Black config

# Enable rules that match your flake8 plugins
select = ["E", "F", "W", "I", "N", "UP", "B", "C4"]

# Tell Ruff to be compatible with your existing isort config
isort.required-imports = ["from __future__ import annotations"]

[tool.ruff.format]  # formatter config — uses 2026 style guide by default in 0.15+

Step 3: Replace Black, isort, and flake8 Commands

Once Ruff is configured, it covers all three tools. Here is the command mapping:

Old commandRuff equivalent
black .ruff format .
black --check .ruff format --check .
isort .ruff check --select I --fix .
flake8 .ruff check .
flake8 --fix .ruff check --fix .
# Run both linting and formatting in one pass
ruff check . && ruff format .

Step 4: Remove the Old Tools

Once Ruff is working correctly in your project, remove the old dependencies:

# Remove Black, isort, flake8
uv remove black isort flake8 flake8-import-order
# or via pip:
pip uninstall black isort flake8

GitHub Actions CI Setup: Ruff in Under 10 Minutes

Here is a complete GitHub Actions workflow that runs Ruff on every push and pull request using the official astral-sh/ruff-action:

# .github/workflows/ruff.yml
name: Ruff

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: astral-sh/setup-uv@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: uv sync

      - name: Run Ruff linter
        run: ruff check .

      - name: Run Ruff formatter check
        run: ruff format --check .

Adding a Pre-Commit Hook

For developer-level enforcement, add Ruff to your .pre-commit-config.yaml so unformatted code never reaches your commit history:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.15.0
    hooks:
      - id: ruff-format      # replaces black
      - id: ruff             # replaces flake8 + isort
        args: [--fix, --select I]  # --fix applies auto-fixes, I = isort rules
# Install pre-commit hooks (run once per developer machine)
uv run pre-commit install

Common Mistakes / Gotchas

  • You are using an older Black config in Ruff: Ruff’s formatter is not identical to Black. If you see unexpected diffs, check the known deviations from Black in the Ruff docs. Most teams accept the small differences as improvements.
  • You did not remove your old .flake8 config: Ruff reads pyproject.toml [tool.ruff] sections, but old .flake8 or setup.cfg files can cause conflicts. Consolidate everything into [tool.ruff].
  • You are on Ruff 0.14: The 2026 style guide ships in Ruff 0.15. If you are pinning an older version, you will not get the new lambda formatting. Run uv tool upgrade ruff to get the latest.
  • You are mixing Ruff config with Black config: Ruff ignores Black’s [tool.black] section in pyproject.toml. Make sure all formatting settings live in [tool.ruff] and [tool.ruff.format].

Summary & Next Steps

Ruff 0.15 with the 2026 style guide is the release that makes Ruff a genuine full-time replacement for Black, isort, and flake8. One binary, one config section in pyproject.toml, and a 10–100x speed improvement over the three-tool stack it replaces. Lambda formatting alone is worth the switch. If you are starting a new project, uv format gives you Ruff 0.15 out of the box with no separate installation needed.

Related posts
Python

Pydantic Agent Basics: A Complete 2026 Tutorial

ProgrammingPython

Production-Ready MCP Servers — Security, Testing & Deployment

ProgrammingPython

Build Your First MCP Server with Python SDK — Fundamentals

ProgrammingPython

Connect FastAPI to MCP — Two Integration Patterns

Leave a Reply