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.
// 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');
| 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 |
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.
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
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.
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
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.
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]' }
The util.types object provides functions for checking the type of JavaScript values. These are more reliable than typeof or instanceof for certain types.
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/));
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.
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
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();
`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.
`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.
`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.
`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.
`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.
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.
Explore 500+ free tutorials across 20+ languages and frameworks.