JavaScript Debugging Tools

Quick debugging one-liners for logging, tracing, timing, and inspecting JavaScript values in any project.

TL;DR

  1. Log values with console.log() and inspect with console.dir().
  2. Pause execution with the debugger statement in DevTools.
  3. Measure performance with console.time() and console.timeEnd() using matching labels.

Logging Basics and Pausing and Tracing

    console.log()

    The default, but other methods solve problems faster.

    console.log('user:', user);
    Labeled logs

    Prefix your logs with a label string as the first arg.

    console.log('type:', typeof myVar);
    console.table()

    Shows an array of objects as a scannable table.

    console.table(users);
    Combined values

    Combine values in one call to compare side by side.

    console.log('before:', before, after);
    debugger;

    Pauses the script wherever DevTools is open.

    debugger;
    console.trace()

    Prints the call stack up to the current line.

    console.trace();
    console.assert()

    Logs when a condition is false.

    console.assert(user.id, 'No id');
    console.count()

    Tallies how many times a line has run.

    console.count('render'); // render: 1

Checking Values

    Strict equality

    Most "why is this undefined" bugs resolve faster with a strict equality check.

    console.log(myVar === undefined);
    Falsy check

    Detect any falsy value with a simple negation check inside an if.

    if (!myVar) console.log('Falsy!');
    typeof

    Use typeof when results seem off, to confirm the value's data type.

    typeof 'hi' === 'string'; // true
    Number.isNaN()

    Checks for NaN without the risky type coercion of the global isNaN().

    Number.isNaN(NaN);  // true
    Number.isNaN('x');  // false

Snapshotting Live Objects

    JSON.stringify snapshot

    console.log(obj) shows the object's state when expanded, not when logged — this fixes that.

    console.log(JSON.stringify(obj, null, 2));
    structuredClone()

    Takes a frozen deep copy for logging without mutating the live original.

    console.log(structuredClone(state));
    console.dir()

    Renders a DOM node as an interactive property tree instead of HTML.

    console.dir(document.querySelector('button'));

Timing and Errors

    console.time/timeEnd

    A matching label is the only thing connecting console.time() to its console.timeEnd().

    console.time('label');
    // code here
    console.timeEnd('label');
    try...catch

    Wrap risky code in a try...catch block to handle errors safely.

    try {
      riskyFunction();
    } catch (e) {
      console.error('Error:', e.message);
    }
    console.error()

    Prints errors in red with a full, clickable stack trace attached.

    console.error('Failed to save:', err);
    console.warn()

    Flags non-fatal issues in yellow so they still catch your eye.

    console.warn('Approaching API rate limit');

Tips

  1. Use console.table() for arrays of objects, since it shows each property as a column for fast visual scanning.
  2. Use the %c format specifier in console.log() to add custom CSS styling to messages, making important output easier to spot.

Warnings

  1. Remove debugger statements and console logs before shipping production code, since they slow down your app and expose data.
  2. console.log() shows a live reference to objects, so an expanded log can differ from the object's state at log time.

In Practice

FAQ