DEV Community

Stack Horizon
Stack Horizon

Posted on

Debugging Node.js Like a Pro

Start with the Right Mindset

Debugging is not about guessing. It's about gathering evidence and narrowing down the problem systematically. In Node.js, the tools are built-in and powerful, but most developers only use console.log. Let's change that.

Use the Built-in Debugger

Node has a built-in debugger that you can start with node inspect. It's a step-by-step command-line debugger. For example:

node inspect app.js
Enter fullscreen mode Exit fullscreen mode

Then you can use commands like cont, next, step, and list. But honestly, the CLI is clunky. The better approach is to use the Chrome DevTools protocol.

Debug with Chrome DevTools

Start your app with --inspect and open chrome://inspect in Chrome. You get a full graphical debugger: breakpoints, watch expressions, call stack, and scope inspection.

node --inspect app.js
Enter fullscreen mode Exit fullscreen mode

For a break at the first line, use --inspect-brk. This is perfect for debugging startup issues.

Use debug for Logging

Instead of sprinkling console.log, use the debug package. It gives namespaced logging that you can turn on/off via the DEBUG environment variable.

const debug = require('debug');
const log = debug('app:server');
const db = debug('app:db');

log('Server starting');
db('Connecting to DB');
Enter fullscreen mode Exit fullscreen mode

Run with DEBUG=app:* node app.js to see all app logs, or DEBUG=app:db to see only DB logs. This keeps your console clean in production.

Handle Unhandled Rejections and Exceptions

Silent failures are the worst. Add global handlers early in your app to catch what you missed.

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  // Application specific logging, throwing an error, or other logic
});

process.on('uncaughtException', (err) => {
  console.error('Uncaught Exception:', err);
  // Best practice: log and exit, because the app is in an unknown state
  process.exit(1);
});
Enter fullscreen mode Exit fullscreen mode

Use node --trace-warnings

If you see warnings about memory or deprecations, run with --trace-warnings to get stack traces for them. This helps identify where the warning originates.

node --trace-warnings app.js
Enter fullscreen mode Exit fullscreen mode

Inspect Memory Leaks

Use the --inspect flag with Chrome DevTools to take heap snapshots. But for quick checks, use process.memoryUsage().

console.log(process.memoryUsage());
Enter fullscreen mode Exit fullscreen mode

For a more detailed look, use the v8 module:

const v8 = require('v8');
console.log(v8.getHeapStatistics());
Enter fullscreen mode Exit fullscreen mode

Use async_hooks for Async Debugging

Async code is hard to trace. The async_hooks module lets you track the lifecycle of async resources. It's advanced but invaluable for finding leaks or lost context.

const async_hooks = require('async_hooks');

const hooks = async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    console.log(`Init ${type} with id ${asyncId}`);
  },
  destroy(asyncId) {
    console.log(`Destroy ${asyncId}`);
  }
});
hooks.enable();
Enter fullscreen mode Exit fullscreen mode

Use it sparingly because it adds overhead.

Use --stack-trace-limit

By default, Node limits stack traces. Increase the limit to see more frames when debugging deep recursion or complex call chains.

node --stack-trace-limit=100 app.js
Enter fullscreen mode Exit fullscreen mode

Use util.inspect for Deep Objects

console.log truncates nested objects. Use util.inspect with full depth.

const util = require('util');
console.log(util.inspect(myObject, { showHidden: false, depth: null, colors: true }));
Enter fullscreen mode Exit fullscreen mode

Debug with ndb (Optional)

ndb is an improved debugging experience for Node.js, built by the Chrome DevTools team. It provides a standalone UI with better navigation. Install it globally and run ndb app.js. It's a nice upgrade over raw Chrome DevTools.

Wrap Up

Stop guessing. Use the built-in tools: --inspect, the debug package, and proper error handlers. These techniques will save you hours and make you a more effective Node.js developer.

Remember: the goal is to understand the problem, not to patch it blindly. Use the tools to see what's happening, then fix the root cause.

Top comments (0)