Skip to content

Node.js Debugging — Complete Guide to Debugging Node.js Applications

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Node.js Debugging. We cover key concepts, practical examples, and best practices to help you master this topic.

Node.js debugging involves inspecting running processes, setting breakpoints, analyzing memory usage, and profiling performance to identify and fix issues efficiently.

What You'll Learn

By the end of this tutorial, you'll use the Node.js built-in debugger, Chrome DevTools, VS Code debugging, memory inspection, CPU profiling, and logging strategies.

Why Debugging Matters

Bugs are inevitable. Knowing how to systematically debug reduces the time spent finding and fixing issues from hours to minutes. Good debugging skills separate experienced developers from beginners.

Real-World Use

An Express.js API suddenly starts responding slowly. Using the built-in inspector and CPU profiling, a developer identifies an N+1 database query and fixes it, reducing response time from 5 seconds to 50ms.

Debugging Learning Path

flowchart LR
  A[Error Handling] --> B[Debugging]
  B --> C[Testing]
  C --> D[Express.js]
  D --> E[Authentication]
  A --> F{You Are Here}
  style F fill:#f90,color:#fff

Built-in Debugger

node inspect app.js
// app.js
function calculate(a, b) {
  debugger;  // Execution pauses here
  const result = a * b + a / b;
  return result;
}
console.log(calculate(10, 5));

Inspect commands: n (next), c (continue), s (step in), repl (evaluate expressions).

Chrome DevTools Debugging

Start Node.js with the --inspect flag:

node --inspect app.js
# Or with break on first line:
node --inspect-brk app.js

Open chrome://inspect in Chrome, click "Open dedicated DevTools for Node". This gives you the full Chrome DevTools experience: breakpoints, call stack, scope variables, and console.

VS Code Debugging

Create a .vscode/launch.json configuration:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/app.js"
    }
  ]
}

Press F5 to start debugging. Set breakpoints by clicking the gutter in VS Code.

Console Logging Strategies

// Use util.inspect for deep objects
import util from "node:util";
const complexObj = { user: { name: "Alice", roles: ["admin", "editor"] } };
console.log(util.inspect(complexObj, { showHidden: false, depth: null, colors: true }));

// Structured logging with JSON
const logEntry = { level: "info", message: "Request received", method: "GET", url: "/api/users", duration: 42 };
console.log(JSON.stringify(logEntry));

Memory Profiling

import v8 from "node:v8";
// Generate heap snapshot
const snapshotStream = v8.getHeapSnapshot();
import fs from "node:fs";
snapshotStream.pipe(fs.createWriteStream("heap.heapsnapshot"));
// Load in Chrome DevTools → Memory → Load

CPU Profiling

node --prof app.js
# Run the app, then:
node --prof-process isolate-*.log > processed.txt

Or use the inspector:

import { Session } from "node:inspector";
const session = new Session();
session.connect();
session.post("Profiler.enable");
session.post("Profiler.start");
// ... run code ...
session.post("Profiler.stop", (err, { profile }) => {
  require("fs").writeFileSync("profile.cpuprofile", JSON.stringify(profile));
});

Common Mistakes

1. Leaving console.log in Production

Use a proper logging library with configurable levels. Too many logs slow down the app and fill disk space.

2. Debugging Without Source Maps

Transpiled code (TypeScript, Babel) shows compiled output without source maps. Enable source maps in your config.

3. Ignoring Memory Leaks

Not monitoring heap growth leads to crashes from out-of-memory errors. Use heap snapshots to find leaked objects.

4. Debugging Only Locally

Bugs in production environments differ from local. Use remote debugging or structured logging for production debugging.

5. Using console.log for Async Flow

Console.log timing can be misleading. Use timestamps and unique request IDs to trace async operations.

Practice Questions

1. What is the difference between node inspect and node --inspect?

node inspect starts the command-line debugger in the terminal. node --inspect enables the Websocket inspector for Chrome DevTools.

2. How do you generate a heap snapshot?

Use v8.getHeapSnapshot() and write the stream to a .heapsnapshot file. Load it in Chrome DevTools Memory tab.

3. What is --inspect-brk?

It pauses execution on the first line, allowing you to set breakpoints before the app starts running.

4. How do you debug an asynchronous callback?

Set a breakpoint inside the callback. Step through using F10/F11 in VS Code or Chrome DevTools.

5. Challenge: Write a script that throws an error intentionally, catches it, and logs a stack trace with a custom message.

function simulateError() {
  try {
    throw new Error("Intentional error for debugging practice");
  } catch (err) {
    console.error("Custom message:", err.message);
    console.error("Stack trace:", err.stack.split("\n").slice(1).join("\n"));
  }
}
simulateError();

FAQ

How do I debug a running Node.js process?

Send SIGUSR1 to enable inspector on a running process: kill -USR1 . Then attach Chrome DevTools.

What is the difference between --inspect and --inspect-brk?

--inspect enables the inspector. --inspect-brk enables it and pauses on the first line of code.

Can I debug Node.js remotely?

Yes. Use --inspect=0.0.0.0:9229 to listen on all interfaces (only in trusted networks).

How do I find memory leaks in Node.js?

Take 3 heap snapshots over time. Compare them in Chrome DevTools to find growing object counts.

What tools help with Node.js profiling?

Node.js --prof, clinic.js (Doctor, Bubbleprof, Flame), 0x flamegraphs, and Chrome DevTools CPU profiler.

Mini Project: Debugging Utility

Create a debugging utility that logs function calls with arguments, results, and execution time.

function createDebugLogger(enabled = true) {
  return function debugLog(fn, fnName = fn.name) {
    return function (...args) {
      if (!enabled) return fn.apply(this, args);
      const start = Date.now();
      console.log(`[DEBUG] ${fnName} called with:`, JSON.stringify(args));
      try {
        const result = fn.apply(this, args);
        const elapsed = Date.now() - start;
        console.log(`[DEBUG] ${fnName} returned:`, JSON.stringify(result), `(${elapsed}ms)`);
        return result;
      } catch (err) {
        console.error(`[DEBUG] ${fnName} threw:`, err.message);
        throw err;
      }
    };
  };
}
const debug = createDebugLogger(true);
const multiply = debug((a, b) => a * b, "multiply");
multiply(4, 5);  // Logs call and result

What's Next

Node.js Testing Express.js Routing Express Middleware

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro