Tutorials Logic, IN info@tutorialslogic.com

Node.js Utilities: inspect, parseArgs, promisify, and Types

What is the Util Module?

The Node.js util module provides a collection of utility functions designed to support the internal APIs of Node.js. While primarily intended for Node.js core modules, these utilities are extremely useful for application developers. The util module includes functions for debugging, formatting strings, type checking, promisifying callback-based functions, and more.

The util module is a built-in Node.js module, so no installation is required. Simply require it in your application to access its powerful utility functions.

Including the Util Module

Require Util Module

Require Util Module
// CommonJS (Node.js)
const util = require('util');

// ES6 Modules (with "type": "module" in package.json)
import util from 'util';

// Import specific functions
const { promisify, format, inspect } = require('util');

Essential Util Module Methods

Method Description Use Case
promisify() Converts callback-based functions to Promise-based Modernizing legacy code
format() Formats strings using printf-like placeholders String formatting and logging
inspect() Converts objects to string representation Debugging and logging objects
types Provides type-checking functions Runtime type validation
deprecate() Marks functions as deprecated with warnings API versioning
callbackify() Converts async functions to callback-based Legacy compatibility
debuglog() Creates conditional debug logging function Development debugging
inherits() Inherits prototype methods (legacy) Pre-ES6 inheritance

1. util.promisify() - Convert Callbacks to Promises

The promisify() function is one of the most useful utilities in modern Node.js development. It converts traditional callback-based functions (following the error-first callback pattern) into Promise-based functions, allowing you to use async/await syntax.

util.promisify() Examples

util.promisify() Examples
const util = require('util');
const fs = require('fs');

// Convert fs.readFile to Promise-based
const readFileAsync = util.promisify(fs.readFile);

// Old callback approach
fs.readFile('file.txt', 'utf8', (err, data) => {
    if (err) throw err;
    console.log(data);
});

// New Promise-based approach
readFileAsync('file.txt', 'utf8')
    .then(data => console.log(data))
    .catch(err => console.error(err));

// Even better: async/await
async function readFile() {
    try {
        const data = await readFileAsync('file.txt', 'utf8');
        console.log(data);
    } catch (err) {
        console.error(err);
    }
}

// Promisify multiple functions
const writeFileAsync = util.promisify(fs.writeFile);
const unlinkAsync = util.promisify(fs.unlink);

async function fileOperations() {
    await writeFileAsync('test.txt', 'Hello World');
    const content = await readFileAsync('test.txt', 'utf8');
    console.log(content);  // Hello World
    await unlinkAsync('test.txt');
}

// Custom callback function
function customCallback(arg, callback) {
    setTimeout(() => {
        callback(null, `Result: ${arg}`);
    }, 1000);
}

const customAsync = util.promisify(customCallback);
customAsync('test').then(console.log);  // Result: test

2. util.format() - String Formatting

The format() function works like printf in C, allowing you to format strings using placeholders. It's commonly used for logging and creating formatted messages.

util.format() Examples

util.format() Examples
const util = require('util');

// %s - String
console.log(util.format('Hello %s', 'World'));
// Output: Hello World

// %d or %i - Integer
console.log(util.format('Number: %d', 42));
// Output: Number: 42

// %f - Floating point
console.log(util.format('Pi: %f', 3.14159));
// Output: Pi: 3.14159

// %j - JSON
const obj = { name: 'Alice', age: 25 };
console.log(util.format('User: %j', obj));
// Output: User: {"name":"Alice","age":25}

// %o - Object (with inspect)
console.log(util.format('Object: %o', obj));
// Output: Object: { name: 'Alice', age: 25 }

// %% - Literal percent sign
console.log(util.format('100%% complete'));
// Output: 100% complete

// Multiple placeholders
console.log(util.format('%s is %d years old', 'Bob', 30));
// Output: Bob is 30 years old

// Extra arguments are concatenated
console.log(util.format('Hello', 'World', '!'));
// Output: Hello World !

// Practical logging example
function log(level, message, ...args) {
    const timestamp = new Date().toISOString();
    const formatted = util.format(message, ...args);
    console.log(`[${timestamp}] [${level}] ${formatted}`);
}

log('INFO', 'User %s logged in from %s', 'alice', '192.168.1.1');
// [2024-01-15T10:30:00.000Z] [INFO] User alice logged in from 192.168.1.1

3. util.inspect() - Object Inspection

The inspect() function converts any JavaScript value into a string representation. It's more powerful than JSON.stringify() because it can handle circular references, functions, symbols, and provides customizable formatting.

util.inspect() Examples

util.inspect() Examples
const util = require('util');

// Basic inspection
const obj = { name: 'Alice', age: 25, active: true };
console.log(util.inspect(obj));
// { name: 'Alice', age: 25, active: true }

// Nested objects with depth control
const nested = {
    user: {
        profile: {
            details: {
                address: '123 Main St'
            }
        }
    }
};

console.log(util.inspect(nested, { depth: 2 }));
// Shows up to 2 levels deep

console.log(util.inspect(nested, { depth: null }));
// Shows all levels (infinite depth)

// Colorized output (for terminal)
console.log(util.inspect(obj, { colors: true }));

// Show hidden properties
const objWithHidden = {};
Object.defineProperty(objWithHidden, 'hidden', {
    value: 'secret',
    enumerable: false
});

console.log(util.inspect(objWithHidden, { showHidden: true }));

// Compact mode (single line)
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(util.inspect(array, { compact: true }));
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// Handle circular references (JSON.stringify would fail)
const circular = { name: 'obj' };
circular.self = circular;
console.log(util.inspect(circular));
// <ref *1> { name: 'obj', self: [Circular *1] }

// Custom inspect function
class User {
    constructor(name, password) {
        this.name = name;
        this.password = password;
    }

    [util.inspect.custom]() {
        return `User { name: '${this.name}', password: '[HIDDEN]' }`;
    }
}

const user = new User('alice', 'secret123');
console.log(util.inspect(user));
// User { name: 'alice', password: '[HIDDEN]' }

4. util.types - Type Checking

The util.types object provides functions for checking the type of JavaScript values. These are more reliable than typeof or instanceof for certain types.

util.types Examples

util.types Examples
const util = require('util');

// Check if value is a Promise
const promise = Promise.resolve(42);
console.log(util.types.isPromise(promise));  // true
console.log(util.types.isPromise({}));       // false

// Check if value is a Date
const date = new Date();
console.log(util.types.isDate(date));        // true
console.log(util.types.isDate('2024-01-01')); // false

// Check if value is a RegExp
const regex = /test/;
console.log(util.types.isRegExp(regex));     // true
console.log(util.types.isRegExp('/test/'));  // false

// Check if value is an async function
async function asyncFn() {}
function normalFn() {}
console.log(util.types.isAsyncFunction(asyncFn));  // true
console.log(util.types.isAsyncFunction(normalFn)); // false

// Check typed arrays
const buffer = Buffer.from('hello');
const uint8 = new Uint8Array([1, 2, 3]);
console.log(util.types.isUint8Array(uint8));       // true
console.log(util.types.isArrayBuffer(buffer));     // false

// Check if value is a Map or Set
const map = new Map();
const set = new Set();
console.log(util.types.isMap(map));  // true
console.log(util.types.isSet(set));  // true

// Practical validation function
function validateInput(value) {
    if (util.types.isPromise(value)) {
        return 'Promise detected - await it first';
    }
    if (util.types.isDate(value)) {
        return `Valid date: ${value.toISOString()}`;
    }
    if (util.types.isRegExp(value)) {
        return `RegExp pattern: ${value.source}`;
    }
    return 'Unknown type';
}

console.log(validateInput(new Date()));
console.log(validateInput(/test/));

5. util.deprecate() - Mark Functions as Deprecated

The deprecate() function wraps a function to emit a deprecation warning when it's called. This is useful for API versioning and guiding users away from old functions.

util.deprecate() Examples

util.deprecate() Examples
const util = require('util');

// Old function
function oldFunction() {
    return 'This is the old way';
}

// Wrap with deprecation warning
const deprecatedFunction = util.deprecate(
    oldFunction,
    'oldFunction() is deprecated. Use newFunction() instead.',
    'DEP0001'  // Optional deprecation code
);

// First call shows warning, subsequent calls don't repeat it
deprecatedFunction();
// (node:1234) [DEP0001] DeprecationWarning: oldFunction() is deprecated. Use newFunction() instead.

// Practical example: API versioning
class API {
    // New method
    getUser(id) {
        return { id, name: 'Alice' };
    }

    // Deprecated method
    fetchUser = util.deprecate(
        function(id) {
            return this.getUser(id);
        },
        'fetchUser() is deprecated. Use getUser() instead.'
    );
}

const api = new API();
api.fetchUser(1);  // Shows deprecation warning
api.getUser(1);    // No warning

Practical Real-World Example

Complete Util Module Example

Complete Util Module Example
const util = require('util');
const fs = require('fs');

// Promisify file operations
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

// Custom logger using util.format
class Logger {
    log(level, message, ...args) {
        const timestamp = new Date().toISOString();
        const formatted = util.format(message, ...args);
        console.log(`[${timestamp}] [${level}] ${formatted}`);
    }

    info(message, ...args) {
        this.log('INFO', message, ...args);
    }

    error(message, ...args) {
        this.log('ERROR', message, ...args);
    }

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

// Main application
async function main() {
    const logger = new Logger();

    try {
        logger.info('Reading configuration file...');
        const config = await readFile('config.json', 'utf8');
        const parsed = JSON.parse(config);

        logger.info('Configuration loaded: %j', parsed);
        logger.debug(parsed);

        // Process data
        const result = {
            status: 'success',
            data: parsed,
            timestamp: new Date()
        };

        await writeFile('output.json', JSON.stringify(result, null, 2));
        logger.info('Output written successfully');

    } catch (err) {
        logger.error('Error occurred: %s', err.message);
        logger.debug(err);
    }
}

main();

Inspection and Formatting

`util.inspect()` produces a debugging representation of JavaScript values, including nested objects, maps, sets, circular references, and custom inspection hooks. Control depth, array and string limits, colors, sorting, compact layout, and line width for the destination. Its output is for humans and can change between Node versions; never parse it as a storage or wire format.

`util.format()` and `formatWithOptions()` apply placeholders and inspection rules. Use them for developer messages, not for building SQL, shell commands, HTML, or structured logs. A formatted object can expose tokens, headers, private fields, or enormous buffers, so redact first and set conservative inspection limits.

A class can implement `util.inspect.custom` to make REPL and logs clearer, but the hook is executable code. Keep it side-effect free, bounded, and secret-aware. A custom display should not be confused with serialization or a security boundary.

  • Treat inspect output as version-dependent debugging text.
  • Bound depth, arrays, strings, and break length.
  • Redact sensitive fields before formatting.
  • Keep custom inspection deterministic and side-effect free.

Callback Adapters

`util.promisify()` adapts a function whose final argument follows the Node error-first callback convention. It does not make blocking work asynchronous and does not understand callbacks with multiple success values unless the API provides a custom promisified form. Prefer a native promise API when Node already supplies one.

Methods that depend on `this` must be bound before or after promisification. Calling a detached method can fail because its receiver is undefined. Do not promisify a function that already returns a promise; current Node documentation marks that use as deprecated and it can hide a mistaken API contract.

`util.callbackify()` adapts an async function for callback consumers. Rejections become the error argument, and falsy rejection reasons require special handling. Keep the adapter at the compatibility edge and preserve one canonical promise-based implementation rather than maintaining two independent code paths.

  • Promisify only standard error-first callback APIs.
  • Bind methods that depend on their receiver.
  • Use native promise variants when available.
  • Keep callbackify at legacy integration boundaries.

Command Argument Parsing

`util.parseArgs()` converts command-line arguments into declared boolean and string options plus positional values. Define long names, short aliases, multiple-value behavior, defaults, strictness, and whether positional values are allowed. The returned values describe syntax; application code still validates files, URLs, numbers, enums, and required combinations.

Enable tokens when building advanced behavior such as preserving option order or explaining an error at the original argument. Support `--` as the option terminator when positionals may begin with a hyphen. Print usage to standard output for an explicit help request and to standard error for invalid input, then set a meaningful exit code.

`util.parseEnv()` parses dotenv-style content in supported Node lines, but parsing a file does not make its values trusted. Validate required variables, distinguish empty from absent, and never print secret values in startup diagnostics. Environment precedence should be an application decision documented outside the parser.

  • Declare supported options and reject unknown input.
  • Validate semantic types after parseArgs returns.
  • Use tokens only when custom CLI behavior needs source detail.
  • Validate and redact parsed environment configuration.

Utility Selection

`util.types` can identify built-in objects such as native promises, proxies, and boxed primitives without relying on spoofable string tags. These checks are most useful in low-level libraries and addons; ordinary application validation should describe the domain shape it expects rather than branching on many runtime internals.

Use `util.deprecate()` in a library when callers need a runtime warning while migrating from an old API, but pair it with release notes and a replacement path. Repeated warnings can overwhelm logs, and deprecation does not remove the need for semantic versioning.

Check stability labels and the documentation for the supported Node LTS line before adopting a utility. Node 24 is LTS in July 2026, while Node 26 is Current. Production code should not depend accidentally on an API available only in Current unless the deployment and compatibility policy explicitly allow it.

  • Use util.types for runtime internals, not broad domain validation.
  • Pair runtime deprecation warnings with migration documentation.
  • Prefer stable APIs present in the supported LTS line.
  • Test formatted output and adapters after Node upgrades.

Adapters, Cancellation, and Migration

`util.promisify()` adapts a function that follows Node error-first callback conventions. It cannot infer APIs with several success values, callbacks in a different position, or methods that require their original `this` receiver. Bind methods when necessary and use a custom promisified implementation only when the callback contract is clearly documented and tested.

A promise wrapper does not automatically add cancellation. If the underlying operation accepts an `AbortSignal`, preserve that capability in the promise-facing API and remove listeners during cleanup. If the original operation cannot be cancelled, timing out the caller may leave work running, so resource ownership and late completion still need a policy.

`util.callbackify()` converts an async function for callback consumers and schedules the callback asynchronously. Promise rejection reasons that are falsy require special handling because the callback convention uses a falsy first argument for success. Preserve the original cause and test both synchronous throws and asynchronous rejections at the compatibility boundary.

Keep adapters near legacy integrations instead of spreading mixed callback and promise styles through domain code. Measure and remove the bridge when the supported dependency baseline allows it. A small compatibility layer with contract tests makes runtime upgrades safer than repeated one-off wrappers.

  • Confirm callback shape and receiver before promisifying.
  • Preserve AbortSignal support and cleanup semantics.
  • Test rejection behavior when callbackifying promises.
  • Centralize temporary adapters behind contract tests.
Before you move on

Node.js Util Module Utility Functions Mastery Check

5 checks
  • The Node.js util module provides a collection of utility functions designed to support the internal APIs of Node.js.
  • While primarily intended for Node.js core modules, these utilities are extremely useful for application developers.
  • The util module includes functions for debugging, formatting strings, type checking, promisifying callback-based functions, and more.
  • The util module is a built-in Node.js module, so no installation is required.
  • Simply require it in your application to access its powerful utility functions.

Node JS Questions Learners Ask

Many older Node APIs and third-party packages use error-first callbacks. util.promisify wraps that style so you can use async/await without rewriting the original function. It expects the callback shape to be callback(error, result).

JSON.stringify is for JSON-compatible data and can fail on circular references or omit values such as functions and undefined. util.inspect is designed for debugging JavaScript objects, with options for depth, colors, hidden properties, and compact output. Use inspect when exploring complex Node objects, request data, errors, or custom classes.

util.format substitutes placeholders such as %s, %d, and %j. If the number or type of arguments does not match the placeholders, the output may still print but not say what you intended. This is easy to miss in quick console debugging.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.