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.jsonconfiguration (example) and provides better error handling for connection issues. -
Try using
launchrequest inlaunch.jsoninstead 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 yourGemfileinstead.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 likebreakpointandbinding.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_ENABLEto0.For example, setting this on CI will make
debuggerorbinding.breakraise 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-runtimeto 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_CONSOLEto1 - 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)updown
For example, if you type
s+enterand then hitenteragain, it’ll repeat thestepcommand. -
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 exceptionandcatch [exception]commands can make debugging control-flow related bugs easier:trace exceptionwill print traces when an exception is raisedcatch [exception]will break when the exception is raised
-
Using the combination of
bt [n]andup/downcommands 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.irbas an alternative. - You can use
binding.irbfor light debugging to open a REPL, and then activate debug.gem with itsdebugcommand. - 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!