Node.js Debugging — Complete Guide to Debugging Node.js Applications
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
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