Back to Blog
Node.jsUtilUtilitiesDebugging

Node.js Util Module Guide

Master the Node.js util module for promisification, debugging, formatting, and utility functions.

B
Bootspring Team
Engineering
November 19, 2019
6 min read

The util module provides essential utilities for debugging, formatting, and working with callbacks. Here's how to use it.

promisify#

1const util = require('util'); 2const fs = require('fs'); 3 4// Convert callback-based function to Promise 5const readFile = util.promisify(fs.readFile); 6const writeFile = util.promisify(fs.writeFile); 7 8// Use with async/await 9async function processFile() { 10 const data = await readFile('input.txt', 'utf8'); 11 const processed = data.toUpperCase(); 12 await writeFile('output.txt', processed); 13 console.log('Done!'); 14} 15 16// Custom promisify 17const sleep = util.promisify(setTimeout); 18 19async function delayedLog(message) { 20 await sleep(1000); 21 console.log(message); 22} 23 24// Multiple callback arguments 25const dns = require('dns'); 26const lookup = util.promisify(dns.lookup); 27 28// Returns { address, family } instead of two args 29const result = await lookup('example.com'); 30console.log(result.address, result.family); 31 32// Custom util.promisify.custom 33dns.lookup[util.promisify.custom] = (hostname) => { 34 return new Promise((resolve, reject) => { 35 dns.lookup(hostname, (err, address, family) => { 36 if (err) reject(err); 37 else resolve({ address, family }); 38 }); 39 }); 40};

callbackify#

1const util = require('util'); 2 3// Convert Promise function to callback 4async function fetchData(id) { 5 const response = await fetch(`/api/data/${id}`); 6 return response.json(); 7} 8 9const fetchDataCb = util.callbackify(fetchData); 10 11// Use with callback 12fetchDataCb('123', (err, data) => { 13 if (err) { 14 console.error(err); 15 return; 16 } 17 console.log(data); 18}); 19 20// Useful for legacy APIs 21async function modernFunction(options) { 22 return { success: true, data: options }; 23} 24 25// Expose as callback for compatibility 26module.exports = util.callbackify(modernFunction);

format and formatWithOptions#

1const util = require('util'); 2 3// Printf-style formatting 4console.log(util.format('Hello, %s!', 'World')); 5// 'Hello, World!' 6 7console.log(util.format('Count: %d', 42)); 8// 'Count: 42' 9 10console.log(util.format('Data: %j', { a: 1, b: 2 })); 11// 'Data: {"a":1,"b":2}' 12 13console.log(util.format('Object: %o', { a: 1 })); 14// 'Object: { a: 1 }' 15 16console.log(util.format('Big: %O', { nested: { deep: 1 } })); 17// Full inspection 18 19// Integer formats 20console.log(util.format('Int: %i', 42.5)); 21// 'Int: 42' 22 23// Percent sign 24console.log(util.format('100%% complete')); 25// '100% complete' 26 27// Extra arguments appended 28console.log(util.format('Hello', 'World', '!')); 29// 'Hello World !' 30 31// With options 32console.log( 33 util.formatWithOptions( 34 { colors: true }, 35 'Data: %O', 36 { nested: { value: 42 } } 37 ) 38);

inspect#

1const util = require('util'); 2 3const complexObject = { 4 name: 'Test', 5 nested: { 6 level1: { 7 level2: { 8 level3: { 9 value: 'deep', 10 }, 11 }, 12 }, 13 }, 14 array: [1, 2, 3, 4, 5], 15 fn: function myFunc() {}, 16 date: new Date(), 17}; 18 19// Basic inspection 20console.log(util.inspect(complexObject)); 21 22// With options 23console.log(util.inspect(complexObject, { 24 depth: null, // Unlimited depth 25 colors: true, // Colorize output 26 showHidden: true, // Show non-enumerable 27 maxArrayLength: 10, 28 maxStringLength: 100, 29 breakLength: 80, 30 compact: false, 31 sorted: true, 32})); 33 34// Custom inspect 35class MyClass { 36 constructor(value) { 37 this.value = value; 38 this.secret = 'hidden'; 39 } 40 41 [util.inspect.custom](depth, options) { 42 return `MyClass<${this.value}>`; 43 } 44} 45 46const instance = new MyClass(42); 47console.log(util.inspect(instance)); 48// 'MyClass<42>'

debuglog#

1const util = require('util'); 2 3// Create debug logger 4const debug = util.debuglog('myapp'); 5 6// Only logs when NODE_DEBUG=myapp 7debug('Starting application'); 8debug('Config: %o', { port: 3000 }); 9 10// Multiple sections 11const dbDebug = util.debuglog('myapp:db'); 12const apiDebug = util.debuglog('myapp:api'); 13 14dbDebug('Connecting to database'); 15apiDebug('Processing request'); 16 17// Run with: NODE_DEBUG=myapp node app.js 18// Or: NODE_DEBUG=myapp:* node app.js (all myapp logs) 19 20// Check if enabled 21const log = util.debuglog('myapp', (fn) => { 22 // Called when logging is enabled 23 console.log('Debug logging enabled'); 24});

types#

1const util = require('util'); 2 3// Type checking 4util.types.isDate(new Date()); // true 5util.types.isRegExp(/pattern/); // true 6util.types.isMap(new Map()); // true 7util.types.isSet(new Set()); // true 8util.types.isPromise(Promise.resolve()); // true 9 10// ArrayBuffer types 11util.types.isArrayBuffer(new ArrayBuffer(8)); // true 12util.types.isTypedArray(new Uint8Array(8)); // true 13util.types.isUint8Array(new Uint8Array(8)); // true 14 15// Error types 16util.types.isNativeError(new Error()); // true 17util.types.isNativeError({ message: 'fake' }); // false 18 19// Async types 20util.types.isAsyncFunction(async () => {}); // true 21util.types.isGeneratorFunction(function* () {}); // true 22 23// Proxy 24const proxy = new Proxy({}, {}); 25util.types.isProxy(proxy); // true 26 27// SharedArrayBuffer (if available) 28if (typeof SharedArrayBuffer !== 'undefined') { 29 util.types.isSharedArrayBuffer(new SharedArrayBuffer(8)); // true 30}

deprecate#

1const util = require('util'); 2 3// Mark function as deprecated 4const oldFunction = util.deprecate( 5 function oldWay(x) { 6 return x * 2; 7 }, 8 'oldWay() is deprecated. Use newWay() instead.', 9 'DEP0001' 10); 11 12// Warning printed once on first call 13oldFunction(5); // Prints deprecation warning 14oldFunction(10); // No warning (already shown) 15 16// Mark method 17class OldAPI { 18 constructor() { 19 this.oldMethod = util.deprecate( 20 this._oldMethod.bind(this), 21 'oldMethod() is deprecated' 22 ); 23 } 24 25 _oldMethod() { 26 return 'old'; 27 } 28 29 newMethod() { 30 return 'new'; 31 } 32} 33 34// Suppress warnings 35// NODE_OPTIONS=--no-deprecation node app.js 36// Or: process.noDeprecation = true;

inherits (Legacy)#

1const util = require('util'); 2 3// Legacy inheritance (prefer class syntax) 4function Animal(name) { 5 this.name = name; 6} 7 8Animal.prototype.speak = function () { 9 console.log(this.name + ' makes a sound.'); 10}; 11 12function Dog(name) { 13 Animal.call(this, name); 14} 15 16util.inherits(Dog, Animal); 17 18Dog.prototype.speak = function () { 19 console.log(this.name + ' barks.'); 20}; 21 22// Modern equivalent 23class Animal2 { 24 constructor(name) { 25 this.name = name; 26 } 27 speak() { 28 console.log(this.name + ' makes a sound.'); 29 } 30} 31 32class Dog2 extends Animal2 { 33 speak() { 34 console.log(this.name + ' barks.'); 35 } 36}

getSystemErrorName#

1const util = require('util'); 2const fs = require('fs'); 3 4// Get system error name from errno 5fs.access('/nonexistent', (err) => { 6 if (err) { 7 console.log('Error code:', err.code); 8 console.log('Errno:', err.errno); 9 console.log('System name:', util.getSystemErrorName(err.errno)); 10 // ENOENT 11 } 12}); 13 14// Common error codes 15const errors = [-2, -13, -17, -28]; 16errors.forEach((errno) => { 17 console.log(errno, '->', util.getSystemErrorName(errno)); 18}); 19// -2 -> ENOENT (No such file) 20// -13 -> EACCES (Permission denied) 21// -17 -> EEXIST (File exists) 22// -28 -> ENOSPC (No space left)

parseArgs#

1const { parseArgs } = require('util'); 2 3// Parse command line arguments 4const options = { 5 name: { type: 'string', short: 'n' }, 6 verbose: { type: 'boolean', short: 'v', default: false }, 7 count: { type: 'string', short: 'c' }, 8}; 9 10const { values, positionals } = parseArgs({ 11 options, 12 allowPositionals: true, 13}); 14 15console.log(values); 16// { name: 'test', verbose: true, count: '5' } 17console.log(positionals); 18// ['file1.txt', 'file2.txt'] 19 20// Usage: node app.js --name test -v --count 5 file1.txt file2.txt 21 22// With strict mode 23try { 24 parseArgs({ 25 options, 26 strict: true, // Throw on unknown options 27 }); 28} catch (err) { 29 console.error('Invalid arguments:', err.message); 30}

TextEncoder/TextDecoder#

1const util = require('util'); 2 3// Encode string to Uint8Array 4const encoder = new util.TextEncoder(); 5const encoded = encoder.encode('Hello, World!'); 6console.log(encoded); 7// Uint8Array [ 72, 101, 108, 108, 111, ... ] 8 9// Decode Uint8Array to string 10const decoder = new util.TextDecoder('utf-8'); 11const decoded = decoder.decode(encoded); 12console.log(decoded); 13// 'Hello, World!' 14 15// With different encodings 16const utf16Decoder = new util.TextDecoder('utf-16le'); 17 18// Stream decoding 19const streamDecoder = new util.TextDecoder('utf-8', { stream: true }); 20// Handles incomplete multi-byte sequences

Best Practices#

Promisify: ✓ Convert callback APIs ✓ Use with async/await ✓ Define custom behavior ✓ Handle multiple values Debugging: ✓ Use debuglog for dev ✓ Use inspect for logging ✓ Add custom inspect methods ✓ Format with colors Type Checking: ✓ Use util.types ✓ Check native types ✓ Validate inputs ✓ Handle edge cases Avoid: ✗ Using inherits (use class) ✗ Ignoring deprecation ✗ Complex format strings ✗ Excessive inspection depth

Conclusion#

The util module provides essential utilities for Node.js development. Use promisify for callback-to-promise conversion, debuglog for conditional logging, and inspect for detailed object visualization. The types namespace offers reliable type checking, and parseArgs simplifies CLI argument parsing.

Share this article

Help spread the word about Bootspring