Debugging Ruby with the debug Gem

· 5 min read · Updated March 20, 2026 · beginner
ruby debugging debug-gem rdbg binding-break developer-tools

The debug gem is Ruby’s official debugging solution. It replaces the older lib/debug.rb standard library and gives you a fast, non-intrusive way to inspect your running code. One of its biggest advantages is that it adds zero performance overhead when you are not actively debugging.

Requirements

You need Ruby MRI 2.7 or later. Ruby 3.1 and later ship with the debug gem as a bundled gem, so no separate installation is required for those versions. If you are on Ruby 2.6 or earlier, this gem will not work — consider using byebug or pry-byebug instead.

Installation

For Ruby versions below 3.1, install the gem manually:

gem install debug

Or add it to your Gemfile:

gem "debug", ">= 1.0.0"

Always specify version 1.0.0 or higher. The debug gem below version 1.0.0 is an older, completely different gem that is no longer maintained.

Two Ways to Debug

Source Modification Mode

Add require 'debug' at the top of your file and place binding.break where you want execution to pause:

require 'debug'

def factorial(n)
  return 1 if n <= 1
  n * factorial(n - 1)
end

binding.break  # execution stops here
result = factorial(5)
p result
# => 120

When you run this file, the debugger stops at the binding.break line and opens an interactive console. From there you can inspect variables and step through code.

binding.break has two aliases: binding.b and debugger. All three do exactly the same thing.

CLI Mode with rdbg

If you prefer not to modify your source code, use the rdbg command-line tool:

rdbg target.rb

This starts your script under the debugger immediately, pausing at the first line. You can also attach rdbg to a running process:

rdbg --attach -- rake test

Or open your script in Chrome DevTools:

rdbg --open target.rb

Debug Console Commands

Once the debugger stops, you get an (rdbg) prompt. Here are the most useful commands:

CommandShortDescription
breakbSet a breakpoint
stepsStep into a method
nextnStep over the current line
continuecResume normal execution
infoShow local variables and current frame
p <expr>Evaluate and print an expression
catchBreak when an exception is raised
traceTrace method calls
configShow or change debugger settings

A typical session looks like this:

(rdbg) info locals
=>#0 factorial(n=5) at target.rb:5
%self => main
n => 5
(rdbg) p n * 10
=>50
(rdbg) next

Use info to see what variables are available in the current scope, then use p to evaluate expressions with those variables.

Conditional Breakpoints

You can make a breakpoint conditional by passing a Ruby expression to binding.break:

require 'debug'

counter = 0
10.times do |i|
  binding.break if i == 7  # stop only when i equals 7
  counter += 1
end
p counter
# => 10

Execution pauses only when the condition evaluates to true. This saves you from manually continuing through unwanted stops.

Key Methods

The main API you will use is binding.break, available in three forms:

binding.break           # unconditional breakpoint
binding.b              # alias
debugger               # alias
binding.break if condition  # conditional

You can also inspect the source location of any binding using Binding#source_location, which is part of Ruby’s core API (available since Ruby 2.5):

loc = binding.source_location
p loc  # => ["target.rb", 5]

This returns a two-element array containing the file path and line number.

rdbg Command Options

The rdbg command has several useful flags:

  • rdbg -n target.rb — run in non-stop mode, meaning the debugger starts but does not pause at the first line
  • rdbg --stop target.rb — stop at the very first line before any code executes
  • rdbg --attach target.rb — attach to an already running Ruby process
  • rdbg --open target.rb — open in Chrome DevTools for a visual debugging experience
  • rdbg --port 12345 target.rb — start a debug server on a specific port for remote debugging

Remote Debugging

You can debug Ruby processes running on other machines or in containers by starting a debug server:

rdbg --port 12345 target.rb

This opens a TCP/IP server on port 12345. You can then connect to it from VSCode using the vscode-rdbg extension, or from Chrome DevTools by pointing your browser to the same port.

UNIX domain sockets are also supported if you prefer local connections without network exposure.

Frontend Integrations

The debug gem supports multiple frontends:

FrontendConnection TypeExtra Requirements
Console (rdbg)UDS or TCPNone
VSCodeUDS or TCPvscode-rdbg extension
Chrome DevToolsTCP/IPChrome browser

The built-in console mode works out of the box. For VSCode, install the vscode-rdbg extension and configure a launch.json that points to your running debug server.

Common Gotchas

A few things that trip people up:

Wrong gem version. Always specify >= 1.0.0 in your Gemfile. Older versions are completely different software.

JRuby is not supported. The debug gem is MRI-only. On JRuby, use ruby-debug (a separate gem) instead, which provides equivalent functionality for that runtime.

Ractor support is incomplete. If you are working with Ruby’s experimental concurrency features, be aware that the debugger may not handle all cases correctly.

Thread debugging has edge cases. Most thread scenarios work, but you may encounter quirks in complex threading situations.

require 'debug' placement matters. The debug gem must be required before any code you want to debug. If you require it after your problematic code, that code will not be instrumented.

SIGINT suspends the debugger. Pressing Ctrl-C while the debugger is running suspends execution and drops you into the debug console at the nearest safe point. This is usually helpful, but be aware it can interrupt long-running operations.

See Also

  • Kernel Methods — learn about Kernel#binding and related methods that power the debug gem
  • Ruby Keywords — understand reserved keywords that appear in conditional breakpoints and debugger expressions