Node.js is a practical Node.js topic that becomes clear when you connect the definition to a small working example.
Use this page to understand what happens, why it happens, how to verify it, and what mistake usually breaks the concept.
After reading, practice Node.js with a normal case, a boundary case, and a broken case so the idea becomes usable instead of memorized.
Node.js Util Module Utility Functions should be studied as a practical Node.js backend development lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.
In the node-js > util-modules page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.
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();
Node.js should be learned as a practical Node.js skill, not only as a definition. Start by asking what problem the topic solves, what input or state it receives, what rule it applies, and what visible result proves it worked.
A strong explanation of Node.js includes the normal case, a boundary case, and a failure case. When you practice, write down the before-state, the operation, the after-state, and the reason the result changed.
This lesson was expanded because the audit reported: limited checklist/practice/mistake/FAQ notes . The added notes below focus on clearer explanation, more examples, and concrete practice so the topic is easier to understand from the page itself.
Imagine you are adding Node.js to a small learning project. The first step is to choose the smallest scenario that still shows the main idea. Avoid starting with a large production design; it hides the concept behind too many details.
Next, isolate the moving parts. Name the input, the rule, the output, and the possible error. This habit makes the topic easier to debug because you can see whether the problem is caused by bad data, wrong configuration, incorrect syntax, timing, permissions, or misunderstanding of the rule.
Finally, compare two versions: one correct version and one intentionally broken version. The broken version is valuable because it teaches you how the topic fails in real work, which is usually what interviews and debugging tasks test.
const topic = 'Node.js';
const input = ['normal', 'empty', 'error'];
for (const item of input) {
console.log(`${topic}: handling ${item} case`);
}
// Run with: node node_js.js
async function explainNodeJs() {
try {
const result = await Promise.resolve('Node.js completed');
console.log(result);
} catch (error) {
console.error('Handle the failure path clearly:', error.message);
}
}
explainNodeJs();
Memorizing Node.js as a definition only.
Pair the definition with a small working example and a failure example.
Copying syntax without checking the state before and after.
Write the input state, apply the rule, then inspect the output state.
Ignoring the error path for Node.js.
Create one intentionally broken version and document the symptom and fix.
Memorizing Node.js Util Module Utility Functions without the situation where it is useful.
Connect Node.js Util Module Utility Functions to a concrete Node.js backend development task.
Understand the problem it solves, the input or state it works on, and the visible result that proves the concept is working.
Use one tiny correct example, one boundary example, and one broken example. Compare the output or state after each change.
They often memorize the term without tracing the behavior. Tracing makes the rule easier to remember and debug.
Remember the problem it solves in Node.js backend development, then attach the syntax or steps to that problem.
Explore 500+ free tutorials across 20+ languages and frameworks.