Skip to content

Core 10 util

Core 10 - Util Module

Basic Idea

util is Node's utility drawer Random useful functions that didn't fit anywhere else Promisify , inspect , format , deprecate - the everyday helpers

util.promisify() - Callback to Promise

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

// convert callback-based function to promise-based
const readFile = util.promisify(fs.readFile)

async function main() {
  try {
    const data = await readFile('config.json', 'utf-8')
    console.log('config:', JSON.parse(data))
  } catch (err) {
    console.error('failed to read config:', err.message)
  }
}

promisify() wraps any function that follows the Node callback convention (err, value) => {} - first argument is error , second is result If the callback is called with multiple results , promisify returns an array

// functions with multiple callback arguments
const crypto = require('crypto')
const pbkdf2 = util.promisify(crypto.pbkdf2)

const key = await pbkdf2('password', 'salt', 100000, 64, 'sha512')
// Buffer - single result (others are dropped)

// custom promisify - define custom behavior
const fn = util.promisify(someFunction)
// if someFunction[util.customPromisifyArgs] is set, it maps argument names

Note: in modern Node (14+) , use fs/promises , timers/promises , etc instead of promisifying promisify() is for libraries that haven't updated to native promises

util.callbackify() - Promise to Callback

const util = require('util')

async function fetchData() {
  const response = await fetch('https://api.example.com/data')
  return response.json()
}

// convert to callback-style for compatibility
const fetchDataCallback = util.callbackify(fetchData)

fetchDataCallback((err, data) => {
  if (err) {
    console.error('fetch failed:', err)
    return
  }
  console.log('data:', data)
})

Much less common than promisify Useful when you need to adapt a promise-based API to callback-expecting code If the promise rejects with null or undefined , the error becomes a regular Error

util.inspect() - Object Inspection

const util = require('util')

const complexObj = {
  name: 'server',
  config: { port: 3000, host: '0.0.0.0' },
  nested: { deep: { deeper: { value: 'secret' } } },
  buffer: Buffer.from('hello'),
  date: new Date()
}

// default - nice formatting
console.log(util.inspect(complexObj))

// control depth
console.log(util.inspect(complexObj, { depth: null, colors: true }))

// show hidden (non-enumerable) properties
console.log(util.inspect(complexObj, { showHidden: true }))

// compact output
console.log(util.inspect(complexObj, { compact: true }))

// custom inspection
const customObj = {
  [util.inspect.custom]() {
    return '<CustomObject: hidden>'
  }
}
console.log(util.inspect(customObj)) // '<CustomObject: hidden>'

inspect() is what console.log() calls internally Use it when you need fine-grained control over how objects are displayed Setting depth: null shows everything - dangerous with circular references (infinite loop)

util.format() - printf-Style Formatting

const util = require('util')

// %s - string
console.log(util.format('hello %s', 'world')) // 'hello world'

// %d - number
console.log(util.format('count: %d', 42)) // 'count: 42'

// %i - integer
console.log(util.format('port: %i', 8080)) // 'port: 8080'

// %f - float
console.log(util.format('ratio: %f', 3.14159)) // 'ratio: 3.14159'

// %j - JSON
console.log(util.format('config: %j', { port: 3000 })) // 'config: {"port":3000}'

// %o - optimized object representation
// %O - generic object representation

// %% - literal percent sign
console.log(util.format('completion: %d%%', 75)) // 'completion: 75%'

Less useful now with template literals (\hello ${world}`) Still handy for log formatters where you need consistent output%jcallsJSON.stringify()` - will throw on circular references

util.types - Type Checking

const util = require('util')

console.log(util.types.isDate(new Date()))              // true
console.log(util.types.isRegExp(/test/))                // true
console.log(util.types.isArrayBuffer(new ArrayBuffer(8))) // true
console.log(util.types.isSet(new Set([1, 2, 3])))       // true
console.log(util.types.isMap(new Map()))                 // true
console.log(util.types.isPromise(Promise.resolve()))    // true
console.log(util.types.isNativeError(new Error()))      // true
console.log(util.types.isProxy({}))                      // false (can't detect proxy)

// built-in types only - not classes from your code
console.log(util.types.isTypedArray(new Uint8Array()))   // true

More specific than typeof or instanceof util.types.isProxy() can't detect proxies - that's by design (proxies are transparent) Use for proper type discrimination when building libraries

util.deprecate() - Marking Deprecated Functions

const util = require('util')

// old API that you want to phase out
function oldConnect(config) {
  // ...
}
const connect = util.deprecate(oldConnect, 'connect() is deprecated. Use createConnection() instead.')

// when called:
connect({ host: 'localhost' })
// (node:12345) DeprecationWarning: connect() is deprecated. Use createConnection() instead.

// custom deprecation code
const connectV2 = util.deprecate(
  oldConnect,
  'connect() is deprecated. Use connectV2() instead.',
  'MYAPP001' // custom code for filtering
)
// (node:12345) [MYAPP001] DeprecationWarning: connect() is deprecated. Use connectV2() instead.

// suppress deprecation warnings
// NODE_OPTIONS='--no-deprecation' node app.js

Deprecation warnings print to stderr - once per method name per process Use custom codes (e.g., 'MYAPP001') so consumers can suppress specific warnings Don't use deprecate() for internal-only functions - it's a public API tool

util.inherits() - Legacy (Don't Use)

const util = require('util')
const EventEmitter = require('events')

// OLD WAY - pre-ES6 classes
function MyClass() {
  EventEmitter.call(this)
}
util.inherits(MyClass, EventEmitter)

// MODERN WAY
class MyClass extends EventEmitter {}

util.inherits() was the pre-ES6 way to do inheritance Nobody should use this in 2025+ Use class extends syntax - cleaner , faster , and supported since Node 4

util.TextEncoder and util.TextDecoder

const { TextEncoder, TextDecoder } = require('util')

const encoder = new TextEncoder()
const bytes = encoder.encode('hello') // Uint8Array
console.log(bytes) // Uint8Array(5) [104, 101, 108, 108, 111]

const decoder = new TextDecoder()
const str = decoder.decode(bytes)
console.log(str) // 'hello'

Available globally in Node 11+ and all modern browsers Use instead of Buffer.from(str, 'utf-8').toString() for encoding-agnostic code TextEncoder/TextDecoder are faster than Buffer for pure text operations

Summary

  • promisify() for adapting legacy callback APIs
  • inspect() for detailed object inspection , format() for printf-style strings
  • types for reliable type checking of built-in types
  • deprecate() for marking public API methods as deprecated
  • inherits() is dead - use class extends instead

Prerequisites

next -> core_11_url.md