# node:util

The `node:util` module groups the Node.js helper functions for common data tasks: formatting strings, inspecting objects for debugging, converting callback-style functions to promises, and checking value types at run time. Azion Runtime supports the module through Node.js compatibility. Inside a function, use `util.promisify()` to adapt callback-based code to `async`/`await`, and `util.inspect()` to log structured data.

---

## Examples

Each example is a complete function that imports `util` from `node:util`. The response below each example is the one a deployed function returns.

### Promisify and inspect

This function converts a callback-style function to a promise, awaits it, and logs the result with `util.inspect()`:

```javascript
/**
 * An example of using Node.js Util API in an Azion Function.
 * Support:
 * - Partially supported (Extended by library `util`)
 * @module runtime-apis/nodejs/util/main
 * @example
 * // Build and run with the Azion CLI:
 * azion build
 * azion dev
 */
import util from "node:util";

const myTest = (callback) => {
  try {
    callback(null, "Success!");
  } catch (err) {
    callback(err);
  }
};

/**
 * An example of using the Node.js Util API in an Azion Function.
 * @param {*} event
 * @returns {Promise<Response>}
 */
const main = async (event) => {
  const promisifyTest = util.promisify(myTest);
  const result = await promisifyTest();
  console.log(util.inspect(result, { showHidden: false, depth: null }));

  return new Response("Done!", { status: 200 });
};

export default main;
```

The function logs `"Success!"` and responds with:

```text
Done!
```

### Callback to promise conversion

This function wraps a callback-based API with `util.promisify()` and calls it twice with `await`:

```javascript
import util from "node:util";
import { setTimeout } from "node:timers";

// Simulate a callback-based API
const fetchData = (id, callback) => {
  setTimeout(() => {
    if (id > 0) {
      callback(null, { id, data: `Item ${id}`, timestamp: Date.now() });
    } else {
      callback(new Error("Invalid ID"));
    }
  }, 100);
};

// Convert to promise-based
const fetchDataAsync = util.promisify(fetchData);

const main = async (event) => {
  try {
    // Now can use with async/await
    const result1 = await fetchDataAsync(1);
    const result2 = await fetchDataAsync(2);

    console.log("Result 1:", result1);
    console.log("Result 2:", result2);

    return new Response(JSON.stringify({ results: [result1, result2] }), {
      headers: { "Content-Type": "application/json" }
    });
  } catch (error) {
    console.error("Error:", error.message);
    return new Response(JSON.stringify({ error: error.message }), {
      status: 400,
      headers: { "Content-Type": "application/json" }
    });
  }
};

export default main;
```

The function responds with both results:

```json
{"results":[{"id":1,"data":"Item 1","timestamp":1767268800000},{"id":2,"data":"Item 2","timestamp":1767268800000}]}
```

The two timestamps are equal because, in a deployed function, `Date.now()` does not advance during a request.

### Deep object inspection

This function inspects request details and a nested object, and builds a string with `util.format()`:

```javascript
import util from "node:util";

const main = async (event) => {
  // Complex object to inspect
  const requestInfo = {
    url: event.request.url,
    method: event.request.method,
    headers: Object.fromEntries(event.request.headers),
    timestamp: new Date().toISOString()
  };

  // Nested object
  const complexData = {
    level1: {
      level2: {
        level3: {
          value: "deep",
          array: [1, 2, { nested: true }]
        }
      }
    }
  };

  // Inspect with options
  const inspected = util.inspect(requestInfo, {
    depth: null,        // Unlimited depth
    colors: false,      // Explicitly disabled since output goes into JSON response
    compact: false,     // Multi-line output
    showHidden: false,  // Don't show non-enumerable
    maxArrayLength: 10  // Limit array display
  });

  console.log("Request info:", inspected);

  // Format string with placeholders
  const formatted = util.format(
    "Request %s to %s at %s",
    requestInfo.method,
    requestInfo.url,
    requestInfo.timestamp
  );
  console.log(formatted);

  return new Response(JSON.stringify({
    requestInfo,
    formatted,
    inspectedDepth: util.inspect(complexData, { depth: 2 })
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

For a `GET` request to `https://example.com/`, the function responds with the request details, the formatted string, and the inspected object:

```json
{"requestInfo":{"url":"https://example.com/","method":"GET","headers":{"accept":"*/*","cdn-loop":"azion.com; steps=1","host":"example.com","user-agent":"curl/8.7.1","x-forwarded-for":"192.0.2.10","x-forwarded-source-port":"6109"},"timestamp":"2026-01-01T12:00:00.000Z"},"formatted":"Request GET to https://example.com/ at 2026-01-01T12:00:00.000Z","inspectedDepth":"{\n  \"level1\": {\n    \"level2\": {\n      \"level3\": {\n        \"value\": \"deep\",\n        \"array\": [\n          1,\n          2,\n          {\n            \"nested\": true\n          }\n        ]\n      }\n    }\n  }\n}"}
```

In Azion Runtime, `util.inspect()` prints `complexData` as indented JSON text with every level expanded, although the call passes `depth: 2`.

### String formatting and deprecation

This function formats strings with placeholders, marks a function as deprecated with `util.deprecate()`, and calls it:

```javascript
import util from "node:util";

// Mark a function as deprecated
const oldFunction = util.deprecate(
  () => "This is the old function",
  "oldFunction is deprecated. Use newFunction instead."
);

const newFunction = () => "This is the new function";

const main = async (event) => {
  const results = [];

  // String formatting with %s, %d, %j, %%
  results.push(util.format("Hello %s!", "World"));
  results.push(util.format("Number: %d, String: %s", 42, "test"));
  results.push(util.format("JSON: %j", { key: "value" }));
  results.push(util.format("Percent: %%"));

  // Style strings (for console output)
  // Note: ANSI codes are only meaningful in terminal output
  // They will appear as escape sequences in HTTP responses
  const styled = util.format(
    "%s %s %s",
    "\x1b[31mRed\x1b[0m",
    "\x1b[32mGreen\x1b[0m",
    "\x1b[34mBlue\x1b[0m"
  );
  console.log(styled); // Useful in logs only

  // Call the deprecated function and its replacement
  const oldResult = oldFunction();
  const newResult = newFunction();

  // Get object's own property names
  const obj = { a: 1, b: 2, c: 3 };
  const keys = Object.keys(obj);

  return new Response(JSON.stringify({
    formattedStrings: results,
    oldFunctionResult: oldResult,
    newFunctionResult: newResult,
    objectKeys: keys
    // Note: styled string not included - ANSI codes not useful in JSON
  }), {
    headers: { "Content-Type": "application/json" }
  });
};

export default main;
```

The function responds with the formatted strings and the result of each function:

```json
{"formattedStrings":["Hello World!","Number: 42, String: test","JSON: {\"key\":\"value\"}","Percent: %"],"oldFunctionResult":"This is the old function","newFunctionResult":"This is the new function","objectKeys":["a","b","c"]}
```

The `%s`, `%d`, `%j`, and `%%` placeholders work as the example shows. The `%i` placeholder is not replaced: `util.format()` leaves `%i` in the output as written.

---

## Supported APIs

The table lists the status of each `node:util` API in Azion Runtime:

| API                               | Status                          |
| --------------------------------- | ------------------------------- |
| `util.promisify()`                | 🟢 Supported                    |
| `util.inspect()`                  | 🟢 Supported                    |
| `util.format()`                   | 🟢 Supported                    |
| `util.deprecate()`                | 🟢 Supported                    |
| `util.isDeepStrictEqual()`        | 🟢 Supported                    |
| `util.inherits()`                 | 🟡 Deprecated (use ES6 classes) |
| `util.callbackify()`              | 🟡 Partially supported          |
| `util.formatWithOptions()`        | 🟡 Partially supported          |
| `util.getSystemErrorMap()`        | 🟡 Partially supported          |
| `util.getSystemErrorName()`       | 🟡 Partially supported          |
| `util.log()`                      | 🟡 Partially supported          |
| `util.stripVTControlCharacters()` | 🟡 Partially supported          |
| `util.styleText()`                | 🟡 Partially supported          |
| `util.types.isDate()`             | 🟢 Supported                    |
| `util.types.isRegExp()`           | 🟢 Supported                    |
| `util.types.isPromise()`          | 🟢 Supported                    |
| `util.types.isArrayBuffer()`      | 🟢 Supported                    |
| `util.types.isNativeError()`      | 🔴 Not supported                |
| `util.types.isTypedArray()`       | 🟢 Supported                    |
| `util.types.isMap()`              | 🟢 Supported                    |
| `util.types.isSet()`              | 🟢 Supported                    |
| `util.types.isCryptoKey()`        | 🟢 Supported                    |
| `util.types.isKeyObject()`        | 🟢 Supported                    |

APIs marked 🟡 Partially supported have limited functionality compared to the full Node.js implementation.

`util.types` checks a value's type at run time, as an alternative to `instanceof`. `util.types.isDate()`, `util.types.isPromise()`, and `util.types.isRegExp()` return `true` for a matching value. `util.types.isNativeError()` throws `Error: [unenv] util.types.isNativeError is not implemented yet!` in a deployed function and under `azion dev`.

Node.js deprecates `util.inherits()` from v5.0.0; use `class` syntax with `extends` instead. In Azion Runtime, `EventEmitter` from `node:events` is a class, so a constructor function that calls `EventEmitter.call(this)` to inherit from it throws `TypeError: Class constructor e cannot be invoked without 'new'`.

---

## Related resources

- [Node.js APIs](/en/documentation/devtools/runtime/node.md): The status of every Node.js module in Azion Runtime, `util` included.
- [Use Node.js APIs through polyfills](/en/documentation/guides/application-development/functions-and-runtime/use-polyfills.md): How the build turns `node:` imports into code that runs in Azion Runtime.
- [node:events](/en/documentation/devtools/runtime/node/events.md): The `EventEmitter` class to extend with `class` syntax instead of `util.inherits()`.
- [Node.js util documentation](https://nodejs.org/api/util.html): The full Node.js reference for every `node:util` API in the table.
