# 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~/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
~/shop $ rubocop --diff lib/greeter.rb Inspecting 1 file C ... 1 file inspected, 5 offenses detected, 4 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
~/shop $ rubocop -a 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: [Corrected] 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:3:12: C: [Corrected] Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols. name = "stranger" if name.nil? ^^^^^^^^^^ lib/greeter.rb:4:14: C: [Corrected] Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols. name = "stranger" ^^^^^^^^^^ lib/greeter.rb:6:5: C: [Corrected] Style/RedundantReturn: Redundant return detected. return "Hello, #{name}!" ^^^^^^ lib/order.rb:3:5: W: [Corrected] Lint/UselessAssignment: Useless assignment to variable - discount. discount = 0.1 ^^^^^^^^ lib/order.rb:3:5: W: [Corrected] Lint/Void: Literal 0.1 used in void context. 0.1 ^^^ 3 files inspected, 7 offenses detected, 6 offenses corrected
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.
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.
~/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.
# .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/**/*
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.
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
Where it runs
On your machine, in your editor, in CI and, these days, inside your coding agent. The output fits wherever it ends up.
- --lsp
- A built-in language server: offenses as you type and format-on-save in VS Code, RubyMine, Emacs, Neovim, Helix, Zed and friends.
- --format github
- Offenses show up as annotations on pull requests.
sariffeeds code scanning,junitthe rest of CI. - --changed
- Only looks at the files git says changed.
- --mcp
- Inspection and autocorrection for coding agents, over the Model Context Protocol.
- --server
- Keeps a warm process around, so runs start instantly.
~/shop $ rubocop -f offenses 1 Lint/UselessAssignment [Safe Correctable] 1 Naming/MethodName 1 Style/IfUnlessModifier [Safe Correctable] 1 Style/RedundantReturn [Safe Correctable] 1 Style/StringLiterals [Safe Correctable] -- 5 Total in 2 files
~/shop $ rubocop -f worst 4 lib/greeter.rb 1 lib/order.rb -- 5 Total in 2 files
~/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`.
~/shop $ rubocop -f json | jq '.files[1].offenses[0]' { "severity": "convention", "message": "Use snake_case for method names.", "cop_name": "Naming/MethodName", "corrected": false, "correctable": false, "location": { "start_line": 2, "start_column": 7, "last_line": 2, "last_column": 14, "length": 8, "line": 2, "column": 7 } }
News
A new release lands every few weeks. The changelog has every detail, and the bigger ones get a write-up on Meta Redux.
- 2026-09-11 RuboCop 1.91: The Journey to 2.0 Beginspost
-
2026-09-10
1.91.0: 10 new features, 55 bug fixes, 13 changes
new: Lint/MisplacedMagicComment -
2026-08-24
1.90.0: 10 new features, 35 bug fixes, 10 changes
new: Lint/ArgumentMismatch, Lint/SuperArgumentMismatch, Style/TimeNow, ... - 2026-08-05 RuboCop 1.89: Project-Wide Analysis with Rubydexpost
-
2026-08-04
1.89.0: 11 new features, 39 bug fixes, 23 changes
new: Lint/DeprecatedReference, Lint/NameTypo, Lint/UnusedPrivateMethod - 2026-07-08 1.88.2: 29 bug fixes, 8 changes
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.
- afbead3 2012-04-21 Initial commit to rubocop.
-
237292d
2013-05-28
0.8 moves onto the
parsergem - 453e12c 2013-07-01 0.9 adds autocorrection and formatters
- ------- 2018-05-31 RuboCop moves to its own GitHub org (RubyKaigi 2018)
- f74c118 2020-10-21 1.0, exactly 7.5 years after the first commit
- 80485d2 2023-06-23 1.53 ships a built-in language server
- 96989aa 2025-02-14 1.72 introduces the plugin system
- 9c2bc8e 2025-03-26 1.75 makes Prism the default parser for Ruby 3.4+
- 6eee0af 2026-09-10 1.91 starts the road to 2.0
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.