articles / Debugging JavaScript in the Browser

Debugging JavaScript in the Browser

Debugging JavaScript in the Browser

Most debugging is done with scattered console.log calls, then deleting them afterward. It works, but the browser ships a real debugger that finds problems faster and shows far more. Learning a handful of its features changes how it feels to track down a bug.

Breakpoints beat logging

A breakpoint pauses execution on a line so you can inspect everything at that exact moment: every variable in scope, the arguments, and the chain of calls that led there. Set one by clicking a line number in the Sources panel, or drop a debugger; statement in the code and it pauses there whenever devtools is open.

function total(items) {
  debugger; // execution pauses here
  return items.reduce((sum, i) => sum + i.price, 0);
}

While paused you can hover any variable to see its value, edit values live in the console, and step through line by line. That single-stepping is what reveals the moment a value becomes wrong, which a log after the fact cannot show.

The call stack and scope

When execution is paused, the call stack panel shows how the code got to this point, frame by frame. Clicking a frame moves the inspector to that function so its local variables become visible. This is the fastest way to answer who called this with these arguments, a question logging rarely answers cleanly.

Stepping controls: step over runs the next line without diving into its function calls; step into enters a called function; step out finishes the current function and pauses at the caller.

Smarter breakpoints

Plain breakpoints are only the start. A conditional breakpoint pauses only when an expression is true, so you can stop on the one iteration that matters instead of clicking through a thousand. A logpoint prints a message without pausing and without editing the source, which replaces temporary console logs entirely. DOM breakpoints pause when an element changes, and event listener breakpoints pause when a specific event fires, which is invaluable when you do not know which handler is responsible.

// right-click a breakpoint -> Edit, add a condition:
i === target.id

The network and console panels

Many bugs are not in the JavaScript at all but in the data. The network panel shows every request, its status, timing, and the exact response body, which quickly distinguishes a front-end mistake from a bad or missing API response. The console doubles as a live workspace: you can run expressions against the current page, inspect objects with console.table for arrays of records, and group related output. Used together, breakpoints for logic and the network panel for data cover the large majority of front-end bugs without adding a single permanent log line.

Debugging code that was built

Shipped JavaScript is usually bundled and minified, so the code in the Sources panel looks nothing like what you wrote. Source maps fix this. A build step emits a map that tells the browser how the minified output corresponds to the original files, and devtools then shows your real source while debugging the deployed bundle.

If breakpoints land on unreadable single-line code, the map is missing or not being served, and that is the first thing to check. Most build tools generate source maps with one setting. The same applies to stack traces in error reports: without maps the line numbers point at the bundle and are useless, while with maps they point back at the real file and line, which is what makes a production error actionable.

None of this requires installing anything. The debugger is already in the browser, and a short investment in learning it pays back on every bug after.

Common questions

Is console.log bad for debugging?

It is fine for quick checks, but breakpoints show every variable in scope at a moment plus the full call stack, and they let you step through line by line. For anything non-trivial they are faster and reveal more.

What is a conditional breakpoint?

A breakpoint that pauses only when an expression you provide is true. It lets you stop on the specific iteration or state that causes a bug instead of clicking through every pass.

How do I debug a problem that looks like bad data?

Open the network panel and inspect the request status, timing, and response body. That quickly tells you whether the bug is in your code or in a wrong or missing API response.

What does the debugger statement do?

When devtools is open, a debugger; statement in your code acts as a breakpoint and pauses execution there. When devtools is closed it is ignored, so it is handy but should be removed before shipping.