Debugging Ruby with Byebug and Pry
Fast recall
Quick revision
Core answer
binding.pry exposes the local variables and methods available at that line. The pry-byebug extension adds stepping and stack navigation to Pry. Put a breakpoint just before the value becomes wrong, reproduce the smallest failing case, inspect inputs before changing them, and remove temporary breakpoints before committing. On modern Rails, also know that the bundled debug gem is the current default debugger.Whether you know `byebug`/`binding.pry` pause execution for inspection, and the difference (byebug steps; pry explores).
Leaving byebug/binding.pry in committed code (pauses production), or debugging with puts everywhere (use a debugger).
byebug/binding.pry pause execution for inspection. byebug steps (next/step/continue); pry explores (REPL, show-source). pry-byebug combines. Remove before committing.
Interview-ready guide
Interview answer
Byebug is a source-level debugger for CRuby, while Pry is an interactive developer console. A Byebug stop gives execution controls and the current call stack. binding.pry opens a Ruby REPL at that exact binding, so local variables, instance variables, methods, and trial expressions can be inspected without adding many print statements.
I start from a reproducible symptom and put the stop immediately before the first suspicious transformation. At the prompt, I read the inputs rather than modifying them first. next executes the next line in the current frame, step enters a called method or block, finish runs until the current frame returns, and continue resumes until another breakpoint or program exit.
For example, if an invoice total becomes zero, I can stop before discount.apply(subtotal), inspect subtotal and discount, step into apply, and compare the returned value with the method's contract. That tells me whether the bad value arrived from the caller or was created inside the discount code.
Pry is strongest for exploration: ls shows available state and show-source can display a method's implementation. The pry-byebug extension supplies stepping and frame commands inside that console. Plain Byebug is enough when execution control matters more than a rich REPL.
Debugging sessions can change in-memory state and hold a web request open, so I use them in development or controlled tests, never as a production repair technique. I remove temporary stops after the cause is understood and add a focused regression test. In current Rails applications I would also consider the bundled debug gem, whose debugger or binding.break entry points serve the same modern workflow.
Debugging Ruby with Byebug and Pry
Direct Answer
Byebug pauses a running Ruby program and lets you inspect the current stack frame, set breakpoints, step into or over calls, and continue execution. Pry is an interactive Ruby console that can open at a specific binding, so binding.pry exposes the local variables and methods available at that line. The pry-byebug extension adds stepping and stack navigation to Pry. Put a breakpoint just before the value becomes wrong, reproduce the smallest failing case, inspect inputs before changing them, and remove temporary breakpoints before committing. On modern Rails, also know that the bundled debug gem is the current default debugger.
Deep Dive & Architecture
Interactive debugging is most effective after the problem has a stable reproduction. A breakpoint placed at a random controller line exposes a great deal of state but no clear question. Instead, identify the last value known to be correct and stop just before the next operation. The session then tests a concrete hypothesis: whether the caller supplied bad input, the callee transformed it incorrectly, or a side effect changed shared state.
At a stop, the debugger selects one stack frame. Expressions typed at the prompt are evaluated in that frame's context, so they can read locals and instance variables visible there. next advances without descending into ordinary calls; step follows a call into its implementation; finish returns to the caller; stack commands reveal how execution reached the point. Changing a variable can be useful for an experiment, but the observation should be repeated from a clean run before treating it as evidence.
Pry focuses on understanding the runtime object model. binding.pry pauses within a particular lexical and object context, ls lists reachable methods and variables, and show-source finds Ruby method source when available. Adding pry-byebug supplies breakpoints, frame movement, and execution controls. Command names and aliases can differ by tool version, so help is safer than relying on a remembered single-letter alias.
A Rails request paused in a terminal has not completed. The browser may appear to hang, database locks may remain open, and another request can observe partial conditions depending on transaction boundaries. That is acceptable in a local environment and dangerous in a shared one. Remote production debugging also exposes application data and execution control, so logs, traces, metrics, safe console procedures, or a reproduced test are the normal production tools.
Current Rails-generated CRuby applications include the debug gem in development and test. It uses entry points such as debugger and binding.break and supports modern debugging features. Byebug and Pry remain common in existing projects, which is why a developer should understand their roles, but the project's Gemfile and runtime decide the actual tool rather than a tutorial's age.
The outcome of a session should be durable knowledge. Once the first incorrect state transition is found, explain why the previous tests allowed it, implement the smallest repair, and add an example that fails without the fix. Delete the breakpoint and any secret-bearing scratch output. A debugger shortens investigation; it does not replace a specification or regression test.
Code Example
class Invoice
def initialize(subtotal, discount)
@subtotal = subtotal
@discount = discount
end
def total
# binding.pry # inspect @subtotal, then step into apply
@discount.apply(@subtotal)
end
end
# Byebug alternative in a configured project:
# byebug
# subtotal_after_discount = @discount.apply(@subtotal)
Common Mistakes & Pitfalls
Leaving byebug/binding.pry in committed code (pauses production), or debugging with puts everywhere (use a debugger).
Check your understanding
Answer these without looking back at the article.
- What is the practical difference between `next`, `step`, and `finish`?
- Why should a breakpoint be placed before the suspected state change?
- Why is an interactive debugger unsafe as an ordinary production technique?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.