Skip to main content

The debugger statement

debugger is a statement that sets a breakpoint right inside the code. When the JavaScript interpreter reaches that line, execution pauses and the developer gets access to variable values, stepping, the call stack and the whole execution context.

Theory

TL;DR

  • debugger; pauses execution on its own line, it is the language level equivalent of a breakpoint.
  • The syntax is minimal: one word, no arguments, no parentheses.
  • It fires only when DevTools is open or a debugger is attached, otherwise the line is ignored.
  • While paused you get Scope, Call Stack, a console bound to the paused frame and the Step over, Step into, Step out controls.
  • Putting it under an if is handy: you stop only on the problematic data.
  • debugger must not reach production code: strip it with a linter or a bundler setting.

Quick example

javascript
function sum(a, b) { debugger; // execution will stop on this line return a + b; } sum(2, 3);

What happens:

  1. If DevTools is closed, the code just runs as if debugger were not there.
  2. If DevTools is open, execution stops on the debugger line. You see the program state, the local variables and the call stack.

Syntax

javascript
debugger;

No arguments, no parentheses, just one word. It is a real language statement rather than a function, so you cannot call it as debugger() or pass it around as a value.

Conditional pauses and loops

The most useful pattern is to put debugger behind a condition so that it stops only in the case you care about. The code keeps running normally and halts only when the data is genuinely interesting.

javascript
function checkUser(user) { if (!user.isActive) { debugger; // debug only the problematic users } return user.name; }

The same trick saves you in loops, where stopping on every iteration would be unbearable:

javascript
for (let i = 0; i < 5; i++) { if (i === 3) debugger; // pauses only when i is 3 console.log(i); }

Console output (with DevTools open):

javascript
0 1 2

and then execution stops at i = 3, where you can inspect variables, the stack and the context.

Debugging async/await and error handling

The statement works inside asynchronous functions too. It is a convenient way to see exactly what the server returned before the response body is parsed:

javascript
async function fetchData() { const response = await fetch('https://api.example.com/users'); debugger; // inspect the response before parsing JSON const data = await response.json(); return data; } fetchData();

In the same way debugger goes into a catch block so that you can analyse the error immediately instead of guessing from the console text:

javascript
try { const user = JSON.parse('{"name":"Tom"}'); console.log(user); } catch (err) { debugger; // inspect err right where it happened console.error('Parse failed:', err); }

If the JSON turns out to be malformed, the debugger opens and shows the contents of err, the failing line and the call stack.

What is available while paused

When execution reaches debugger:

  • the program is put on pause,
  • the debugger panel opens in Chrome DevTools or in VS Code,
  • and from there you can:
    • inspect Scope Variables: locals, globals and closure variables,
    • see the Call Stack, the chain of calls that led to this point,
    • run arbitrary code in the Console, in the context of the paused function,
    • move step by step: Step over, Step into, Step out,
    • change variable values while paused and resume execution with the new data.

The difference between debugger and console.log()

Featureconsole.log()debugger
Shows valuesYesYes, in the debugger UI
Pauses executionNoYes
Shows the call stackPartly, via console.trace()Fully
Works without DevToolsYesNo
Lets you change variable stateNoYes, right while debugging

Summary:

QuestionAnswer
What it doesStops code execution on its line
When it firesOnly with DevTools open or a debugger attached
What you can do while pausedInspect variables and the call stack, execute code step by step
When to use itOn tricky logic bugs, once console.log no longer helps
What it does not doPrints nothing to the console and has no effect without DevTools

Common mistakes

  • Leaving debugger; in a production build. For a user with DevTools open the page simply freezes. The no-debugger lint rule plus stripping at build time solves this.
  • Assuming debugger logs something. It prints nothing at all: if you need a trace in the console, that is a separate console.log() or console.trace().
  • Expecting a pause with DevTools closed. Without an open panel or an attached debugger the statement has no effect, and that is not a bug.
  • Putting debugger in a hot loop without a condition. Stopping on every iteration makes debugging impossible; add an if as in the example above.
  • Forgetting that the pause freezes the whole page. Timers, animations and network responses all wait, so any timing measured during a pause is meaningless.
  • Debugging minified code without source maps. debugger will stop, but you will be looking at an unreadable line; enable source maps.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.