rubocop 1.92.0

# The Ruby linter and formatter that serves and protects

RuboCop checks your Ruby code against the community Ruby Style Guide, points out what's off and fixes most of it for you. It knows about bugs, style, layout and complexity, it bends to your team's taste, and it's been at it since 2012.

$gem install rubocop

# optional: rubydex for cross-file checks, mcp for agents

Latest release: 1.92.0 (10 Oct 2026), and the write-up.
New here? Getting started takes five minutes, or try it in your browser first.

~/shop $ rubocop
Inspecting 3 files
.CW

Offenses:

lib/greeter.rb:2:7: C: Naming/MethodName: Use snake_case for method names.
  def sayHello(name)
      ^^^^^^^^
lib/greeter.rb:3:5: C: [Correctable] Style/IfUnlessModifier: Favor modifier if usage when having a single-line body. Another good alternative is the usage of control flow &&/||.
    if name.nil?
    ^^
lib/greeter.rb:4:14: C: [Correctable] Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
      name = "stranger"
             ^^^^^^^^^^
lib/greeter.rb:6:5: C: [Correctable] Style/RedundantReturn: Redundant return detected.
    return "Hello, #{name}!"
    ^^^^^^
lib/order.rb:3:5: W: [Correctable] Lint/UselessAssignment: Useless assignment to variable - discount.
    discount = 0.1
    ^^^^^^^^

3 files inspected, 5 offenses detected, 4 offenses autocorrectable

What it checks

Every check is a cop, and cops live in departments. Lint catches code that's probably a bug, Style, Layout and Naming keep a codebase consistent, Metrics flags methods and classes that got too big, and Security spots the usual footguns.

Most cops come straight from a guideline in the style guide, and most of them can fix what they find.

Normally each cop sees one file at a time. Add the optional rubydex gem and set UseProjectIndex: true under AllCops, and RuboCop indexes the whole project first. The index serves 17 cops: Lint/DuplicateMethods catches a method defined twice in different files, others stop flagging code that's fine once they can see the rest of the project, and a few new ones, like Lint/NameTypo, only work with it. It's experimental and needs Ruby 3.2 or newer.

Browse all the cops → The project index →

Inspecting 613 cops
Style/ 299
Lint/ 160
Layout/ 100
Naming/ 19
on by defaultpending (on in the next major release)opt-in
Each square is a cop. 394 are on by default, 163 are pending until the next major release and 56 are opt-in. Hover one, or tab in and use the arrow keys, to see what it does.

What it fixes

rubocop -a applies the corrections that can't change what your code does. rubocop -A goes further and applies the ones that might, so run it with your tests nearby.

Want to look before you leap? --diff prints the patch and leaves your files alone. The Layout cops make RuboCop a formatter too, and rubocop -x runs just those.

Try it on your own code → How autocorrection works →

~/shop $ rubocop -A --diff
Inspecting 3 files
.CW

...

3 files inspected, 7 offenses detected, 6 offenses corrected

--- a/lib/greeter.rb
+++ b/lib/greeter.rb
@@ -1,8 +1,6 @@
 class Greeter
   def sayHello(name)
-    if name.nil?
-      name = "stranger"
-    end
-    return "Hello, #{name}!"
+    name = 'stranger' if name.nil?
+    "Hello, #{name}!"
   end
 end
--- a/lib/order.rb
+++ b/lib/order.rb
@@ -1,6 +1,5 @@
 class Order
   def total(items)
-    discount = 0.1
     items.sum(&:price)
   end
 end

Make it yours

The defaults follow the style guide, but Ruby has never had one true style and RuboCop doesn't pretend otherwise. Most cops support several styles, and it's all set in a single .rubocop.yml, which can inherit from a shared one.

Adopting it on an old codebase? rubocop --auto-gen-config records every existing offense in .rubocop_todo.yml, so new code meets the standard today and the old debt gets paid off one cop at a time.

For real-world examples, see how Rails, GitLab, Discourse and Mastodon set it up.

Configuration →

# .rubocop.yml
inherit_from: .rubocop_todo.yml

AllCops:
  TargetRubyVersion: 3.4
  NewCops: enable

Style/StringLiterals:
  EnforcedStyle: double_quotes   # we know, we know

Metrics/MethodLength:
  Max: 15
  Exclude:
    - db/migrate/**/*

How it works

RuboCop never runs your code. It parses each file into a syntax tree, with Prism, or with the parser gem for code that targets Ruby older than 3.3. Then it walks the tree once and calls each cop for the kinds of nodes it asked to see.

Most cops are a node pattern and a message. Style/NilComparison asks to see calls to ==, === and nil?, and reports the ones its pattern matches.

Corrections don't touch the tree. A cop rewrites the source where its node came from, and RuboCop parses the result and runs the cops again, until a pass changes nothing. That's how one rubocop -a can sort out code that takes several cops in turn.

Node patterns → Writing your own cops →

# lib/user.rb
return if user == nil

# the tree RuboCop inspects
(if
  (send
    (send nil :user) :==
    (nil))
  (return) nil)

Plugins

The core knows Ruby. Plugins teach it about the frameworks and libraries around it. The RuboCop team maintains the ones on the right, and there are plenty more out there, from rubocop-graphql to rubocop-sorbet.

Writing your own cops is easier than it sounds, and a project can keep a few in-house cops for its own conventions.

All the plugins →

plugins:
  - rubocop-performance    # faster idioms
  - rubocop-rails          # Rails best practices
  - rubocop-rspec          # RSpec
  - rubocop-rspec_rails    # RSpec + Rails
  - rubocop-minitest       # Minitest
  - rubocop-capybara       # Capybara
  - rubocop-factory_bot    # factory_bot
  - rubocop-rake           # Rakefiles
  - rubocop-thread_safety  # thread safety
  - rubocop-sequel         # Sequel
  - rubocop-i18n           # gettext and rails-i18n

In your editor

RuboCop has a language server built in. Your editor gets offenses as you type, a quick fix for each one, and RuboCop's corrections as a formatter, which most editors can run on save. It's the same RuboCop with the same config your CI runs.

Ruby LSP, which the docs recommend for most editors, runs RuboCop for you. Otherwise point your editor's LSP client at rubocop --lsp, or install the vscode-rubocop extension. RubyMine has RuboCop support of its own.

For editors that just shell out to rubocop, --server keeps a warm process around, so each run starts instantly. It isn't available on Windows or JRuby.

Editor setup → The language server →

1class Greeter2  def sayHello (Naming/MethodName: Use snake_case for method names.

This offense is not autocorrectable.)(name)3    if (Style/IfUnlessModifier: Favor modifier `if` usage when having a single-line body. Another good alternative is the usage of control flow `&&`/`||`.) name.nil?4      name = "stranger" (Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.)Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.RuboCop(Style/StringLiterals)Autocorrect Style/StringLiteralsDisable Style/StringLiterals for this line5    end6    return (Style/RedundantReturn: Redundant `return` detected.) "Hello, #{name}!"7  end8end

In your agent

Coding agents run RuboCop far more often than people do, and everything it prints ends up in their context. rubocop --mcp gives them inspection, autocorrection and cop explanations as tools, answered by a RuboCop that's already loaded. It needs the mcp gem.

From the shell, --format json tells an agent which offenses autocorrection can fix and the edits it would make, --explain tells it what a cop wants when the message isn't enough, and --max-offenses-per-cop keeps an old codebase from flooding its context.

An agent told to make RuboCop pass can disable its way there. Enable the cop that polices rubocop:disable comments with AllowWithReason, and every one of them needs a reason, so whoever reviews the change sees why.

RuboCop and coding agents → The MCP server →

~/shop $ rubocop -f json | jq '.files[1].offenses[1]'
{
  "severity": "convention",
  "message": "Favor modifier `if` usage when having a single-line body. Another good alternative is the usage of control flow `&&`/`||`.",
  "cop_name": "Style/IfUnlessModifier",
  "corrected": false,
  "correctable": true,
  "location": {
    "start_line": 3,
    "start_column": 5,
    "last_line": 3,
    "last_column": 6,
    "length": 2,
    "line": 3,
    "column": 5
  },
  "correction": {
    "safe": true,
    "edits": [
      {
        "start_line": 3,
        "start_column": 5,
        "last_line": 5,
        "last_column": 7,
        "begin_pos": 39,
        "end_pos": 83,
        "replacement": "name = \"stranger\" if name.nil?"
      }
    ]
  }
}

In CI

Offenses can land right on the pull request. --format github turns them into annotations, sarif feeds code scanning and junit the rest of CI. --fail-level decides which severities fail the build, and --changed=main... checks only the files a branch changed since it forked.

When there's too much to read, -f offenses and -f worst show where the offenses pile up.

Formatters →

~/shop $ rubocop -f github

::error file=lib/greeter.rb,line=2,col=7::Naming/MethodName: Use snake_case for method names.
::error file=lib/greeter.rb,line=3,col=5::Style/IfUnlessModifier: Favor modifier `if` usage when having a single-line body. Another good alternative is the usage of control flow `&&`/`||`.
::error file=lib/greeter.rb,line=4,col=14::Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
::error file=lib/greeter.rb,line=6,col=5::Style/RedundantReturn: Redundant `return` detected.
::error file=lib/order.rb,line=3,col=5::Lint/UselessAssignment: Useless assignment to variable - `discount`.

News

A new release lands every few weeks. The changelog has every detail, and the bigger ones get a write-up on Meta Redux.

History

I started RuboCop in April 2012 to make it easy to actually follow the Ruby Style Guide, which I'd started a few months earlier. Fourteen years, two parsers and over 1,100 contributors later, it's how a big chunk of the Ruby world keeps its code in shape.

The longer version →

Who's behind it

RuboCop is free and maintained by a small core team of volunteers, with help from thousands of contributors. If your company's code goes through RuboCop every day, consider giving something back. It's what keeps the lights on and the releases coming.

# organizations backing RuboCop on Open Collective

Airbnb Modern Treasury Chef @ Progress Wealthsimple Practice Ignition Coinbase Renuo AG InVision AG Qlty Software Dutchie CodeRabbit Civilized Discourse Construction Kit, Inc. Triplebyte Scout Workleap DigitalOcean uffizzi cloud Algolia Sider, Inc. Agendrix

# and individuals

Jeff Atwood Jeff Atwood Scott Ferreira Mack Earnhardt Rohit Namjoshi Daniel Berger Josh Thurman Katsuhiko YOSHIDA sean shigeru nakajima Stex Jared Smith Jonathon Frisby Adam Doppelt ilvez Mike Stok anonymous Rich Dabrowski Ben Abrams anonymous Sider, Inc. Francis Botero Wayne Xie Koichiro Sumi CindyLiu Larry Kooper Alvin Sng John Manoogian III Derk-Jan Karrenbeld @SleeplessByte Quinn Peh