Guide to util.inspect and Customizing Node.js Object Output

In Node.js, debugging complex objects can be challenging when standard logging outputs generic or truncated data. This article explores the util.inspect function, explaining its primary purpose for stringifying objects for debugging, and demonstrates how to customize its output using configuration options and custom inspection methods.

What is util.inspect?

The util.inspect method is a built-in Node.js utility that returns a string representation of an object. This representation is specifically formatted for debugging and is much more detailed than the default behavior of JSON.stringify or toString(). Under the hood, console.log automatically uses util.inspect to print objects to the terminal.

By default, util.inspect will pretty-print objects, resolve circular references without throwing errors, and colorize output in supported terminals.

Basic Usage and Common Options

You can import util and call inspect directly on any object. The function accepts an optional options object to control the level of detail.

const util = require('util');

const user = {
  name: 'Alice',
  details: {
    age: 30,
    preferences: {
      theme: 'dark',
      notifications: true
    }
  }
};

// Default inspect (stops at depth 2)
console.log(util.inspect(user));

To control how the object is formatted, you can pass several key options:

console.log(util.inspect(user, { depth: null, colors: true }));

How to Customize Object Output

Sometimes, standard formatting is not enough, especially when dealing with classes or objects that contain sensitive data (like passwords) or complex internal states. Node.js allows you to define a custom inspection function using a special Symbol.

Using the Custom Inspect Symbol

You can customize how an object is displayed by assigning a function to the Symbol.for('nodejs.util.inspect.custom') property of your object or class prototype.

When util.inspect encounters an object with this symbol, it will execute your custom function instead of using the default formatting.

const util = require('util');

class DatabaseConnection {
  constructor(host, password) {
    this.host = host;
    this.password = password; // Sensitive data
    this.connected = true;
  }

  // Define the custom inspect method
  [Symbol.for('nodejs.util.inspect.custom')](depth, options, inspect) {
    // Hide the password and format the output
    return `DatabaseConnection { host: '${this.host}', connected: ${this.connected}, password: '[REDACTED]' }`;
  }
}

const db = new DatabaseConnection('localhost', 'secret123');

console.log(db); 
// Output: DatabaseConnection { host: 'localhost', connected: true, password: '[REDACTED]' }

Utilizing Parameters in Custom Inspect

The custom inspect function receives three parameters: 1. depth: The current depth level of the inspection. 2. options: The options object passed to util.inspect. 3. inspect: A reference to the active inspect function itself, which you can use to format nested properties within your custom output.