iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

util

The node:util module is the Swiss Army knife of Node. Promisify, inspect, parseArgs, MIMEType, styleText — small helpers that show up everywhere.

Node — node:util in practice

EXAMPLE
import util from 'node:util';
import fs from 'node:fs';

// ===== promisify =====
// Wrap callback-style APIs so you can await them.
const readFile = util.promisify(fs.readFile);
const text = await readFile('package.json', 'utf8');

// Inverse: callbackify wraps a promise-returning fn back into a callback.
const writeFileCb = util.callbackify(async (p, data) => fs.promises.writeFile(p, data));

// ===== inspect: pretty-print anything =====
const obj = { id: 42, tags: ['a', 'b'], nested: { ok: true } };
console.log(util.inspect(obj, { colors: true, depth: 4, compact: false }));

// Custom inspect on your own class:
class Money {
  constructor(public cents, public currency = 'AUD') {}
  [util.inspect.custom]() { return \`Money(${this.cents/100} ${this.currency})\`; }
}
console.log(new Money(4995)); // -> Money(49.95 AUD)

// ===== parseArgs: built-in CLI flag parser =====
const { values, positionals } = util.parseArgs({
  args: process.argv.slice(2),
  options: {
    verbose: { type: 'boolean', short: 'v' },
    out:     { type: 'string',  short: 'o' },
    tag:     { type: 'string',  multiple: true },
  },
  allowPositionals: true,
});
console.log(values, positionals);
// node app.js build --out dist --tag a --tag b src/
//   -> values = { out: 'dist', tag: ['a', 'b'], verbose: false }
//   -> positionals = ['build', 'src/']

// ===== styleText: ANSI without picking a colour lib =====
import { styleText } from 'node:util';
console.log(styleText('green', 'PASS') + ' ' + styleText(['bold', 'red'], 'FAIL'));
// Honours NO_COLOR, FORCE_COLOR, and tty detection.

// ===== MIMEType =====
const mt = new util.MIMEType('text/HTML; charset=UTF-8');
console.log(mt.type, mt.subtype, mt.params.get('charset')); // text html utf-8

// ===== format and formatWithOptions =====
console.log(util.format('%s scored %d (%o)', 'Alex', 92, { strict: true }));
// %s string, %d number, %j JSON, %o object, %O deep object, %% literal %

// ===== util.types: tagged type checks =====
console.log(util.types.isPromise(Promise.resolve()));  // true
console.log(util.types.isNativeError(new TypeError())); // true
console.log(util.types.isDate(new Date()));             // true

// ===== util.deprecate =====
const oldApi = util.deprecate(
  () => console.log('still works'),
  'oldApi() is deprecated; use newApi() instead',
  'DEP0042',
);
oldApi(); // first call logs the warning; subsequent calls don't repeat

// ===== Patterns to internalise =====
// - util.parseArgs for any script-sized CLI; reach for yargs/commander only when you need subcommands
// - util.styleText for tiny tools; pkg-free
// - util.inspect.custom on domain objects so logs read like a model
// - util.promisify when you must integrate a callback API

// ===== Pitfalls =====
// - util.format is NOT a template tag; '${x}' won't interpolate
// - inspect depth defaults to 2 -> nested data gets truncated; pass depth: null for full
// - parseArgs strict mode rejects unknown flags by default; opt into strict: false if you forward args
// - deprecate runs once per signature; if you change the wrapper, the throttle resets

Why it matters

node:util is the standard library hiding in plain sight. Once parseArgs, styleText, inspect.custom, and promisify are reflexes, you stop reaching for half a dozen tiny packages and ship scripts and tools with zero deps.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import { promisify } from 'node:util';
const sleep = promisify(setTimeout);
await sleep(100);
Try it Yourself »

Discussion

Loading…