Ruby Debugging Tips and Recommendations in 2025
Debugging is a crucial skill for any Ruby developer. And as the tools and techniques evolve, it’s important to keep up-to-date with the latest best practices.
So here are some of my Ruby debugging tips and recommendations that I’d offer to Ruby developers in 2025.
- You can use the Ruby LSP extension to connect to debug.gem too.
It requires a slightly different
launch.json
configuration (example) and provides better error handling for connection issues. -
Try using
launch
request inlaunch.json
instead ofattach
. It simplifies the debugging process as you don’t need to manually start/stop the server. In most Rails projects, a simple entry like this will do:{ "version": "0.2.0", "configurations": [ { "type": "ruby_lsp", "name": "Launch Server", "request": "launch", "program": "bin/rails s", }, ] }
- The effectiveness of your debugging session heavily depends on your ability to navigate between methods, classes, and files.
Make sure you have a good editor setup, such as Ruby LSP.
- Even if you don’t use VS Code, Ruby LSP works with many other editors too.
- Use Ruby LSP’s Code Lens feature to easily debug tests in both terminal and VS Code.
- I made ruby-lsp-rspec to provide code lens for RSpec tests.
-
Use
gem "debug", require: "debug/prelude"
in yourGemfile
instead.debug.gem is activated when required, which usually isn’t necessary when you’re not debugging.
By requiring
debug/prelude
, it defines the breakpoint methods likebreakpoint
andbinding.break
, but doesn’t activate the gem immediately.(This has been the default in newly generated Rails projects since Rails 7.2.)
-
If you want to prevent debug.gem from being used in certain environments, you can set
RUBY_DEBUG_ENABLE
to0
.For example, setting this on CI will make
debugger
orbinding.break
raise an error rather than hang indefinitely. -
You can configure debug.gem to ignore certain gems when debugging. For example:
begin # Try to load debug, but only just the config component so we don't activate it by accident require "debug/config" zeitwerk_paths = Gem.loaded_specs["zeitwerk"].full_require_paths.freeze bootsnap_paths = Gem.loaded_specs["bootsnap"].full_require_paths.freeze DEBUGGER__::CONFIG[:skip_path] = Array(DEBUGGER__::CONFIG[:skip_path]) + zeitwerk_paths + bootsnap_paths rescue LoadError # In case debug.gem is not installed for any reason # Such as when this file being loaded from production where debug.gem is usually not installed end
-
If you use
Sorbet
, you can addsorbet-runtime
to the ignore list too:sorbet_paths = Gem.loaded_specs["sorbet-runtime"].full_require_paths.freeze DEBUGGER__::CONFIG[:skip_path] = Array(DEBUGGER__::CONFIG[:skip_path]) + sorbet_paths
-
- For most users, I recommend activating debug.gem’s integration with IRB for a better debugging experience. You can do this by:
- Setting
RUBY_DEBUG_IRB_CONSOLE
to1
- Setting
DEBUGGER__::CONFIG[:irb_console]
totrue
- Setting
- The following debug.gem commands will repeat when hitting
enter
:step
(s
)next
(n
)continue
(c
)finish
(fin
)until
(u
)up
down
For example, if you type
s
+enter
and then hitenter
again, it’ll repeat thestep
command. -
You can use
debugger(do: "...")
ordebugger(pre: "...")
to automatically execute a command after a breakpoint is hit:# This will print the local variables and open the console debugger(pre: "info locals") # This will print the local variables and continue the program debugger(do: "info locals")
- The combination of
trace exception
andcatch [exception]
commands can make debugging control-flow related bugs easier:trace exception
will print traces when an exception is raisedcatch [exception]
will break when the exception is raised
-
Using the combination of
bt [n]
andup
/down
commands is often more effective than setting multiple breakpoints on the same code path. -
For more fine-grained tracing, you can use the tracer gem.
-
debug.gem freezes all running threads when it enters a breakpoint. If this causes issues, use
binding.irb
as an alternative. - You can use
binding.irb
for light debugging to open a REPL, and then activate debug.gem with itsdebug
command. - For learning more fundamental debugging concepts, I think my talk at RubyKaigi 2022 should still be helpful.
I hope you find these tips useful. Happy debugging!