Node.js Util Module

The Node.js util module bundles a collection of helper utilities for formatting strings, inspecting objects for debugging, and converting older callback-based functions into promise-returning ones.

Overview of the Util Module

util is one of the oldest core modules in Node.js and has accumulated a wide variety of helpers over time. Rather than a single theme, it acts as a home for small, broadly useful tools: string formatting (util.format), object inspection for logging (util.inspect), type checking, deprecation warnings, and adapters between callback style and promise style code (util.promisify and util.callbackify).

util.format for String Formatting

util.format(format[, ...args]) works similarly to C's printf, substituting placeholders like %s (string), %d (number), %j (JSON), and %o (object) in order. Any extra arguments beyond the placeholders are appended to the output separated by spaces, and console.log actually uses util.format internally when called with multiple arguments.

Formatting strings with util.format

const util = require('util');

const message = util.format('User %s logged in with id %d', 'alice', 42);
console.log(message); // User alice logged in with id 42

const withExtra = util.format('Status:', 'ok', { retries: 0 });
console.log(withExtra); // Status: ok { retries: 0 }

util.inspect for Debugging Output

util.inspect(object[, options]) converts any JavaScript value into a human-readable string, which is exactly what console.log does under the hood for non-string arguments. It's especially useful when you need finer control than console.log gives you, such as increasing the depth for deeply nested objects or enabling colorized output.

Inspecting nested objects

const util = require('util');

const data = {
  user: { id: 1, profile: { name: 'Alice', roles: ['admin', 'editor'] } },
};

console.log(util.inspect(data, { depth: null, colors: false }));
// { user: { id: 1, profile: { name: 'Alice', roles: [ 'admin', 'editor' ] } } }

console.log(util.inspect(data, { depth: 0 }));
// { user: [Object] }
  • depth - how many levels of nested objects to expand (default 2, null for unlimited)
  • colors - whether to add ANSI color codes to the output
  • showHidden - whether to include non-enumerable properties and symbols
  • compact - controls how many short properties are grouped onto one line
  • breakLength - the line length at which output starts wrapping

util.promisify for Modernizing Callback APIs

util.promisify(original) takes a function following the classic Node.js callback convention - the last argument is a callback of the form (err, value) - and returns a new function that returns a Promise instead. This is the standard way to bridge old-style APIs like fs.readFile into async/await code without manually wrapping them in `new Promise()`.

Promisifying a callback-based function

const util = require('util');
const fs = require('fs');

const readFile = util.promisify(fs.readFile);

async function main() {
  const contents = await readFile('./package.json', 'utf8');
  console.log(contents.slice(0, 50));
}

main().catch(console.error);

Custom promisify Support

Some libraries define their own promisified variant of a function and expose it via the special util.promisify.custom symbol. When util.promisify encounters a function with that symbol set, it returns the custom implementation instead of generating one automatically, which lets library authors provide a more efficient or accurate promise-based version.

FunctionPurposeTypical Use
util.formatprintf-style string formattingBuilding log messages
util.inspectConvert values to readable stringsDebugging, custom loggers
util.promisifyCallback function to Promise-returning functionModernizing old APIs
util.callbackifyPromise-returning function to callback functionExposing async code to callback consumers
Note: Since Node.js 10, most core modules already ship a promise-based variant (like require('fs').promises or require('dns').promises), so you often don't need util.promisify for built-in APIs anymore - reach for it mainly with third-party or legacy callback-based code.
Note: util.promisify assumes the target function calls its callback exactly once with (err, value). Functions that invoke the callback multiple times, or that don't follow the error-first convention, will produce a promisified wrapper that behaves unpredictably.

Exercise: Node.js Util Module

What does util.promisify() do?