Skip to content
JavaScript Basics: Inspect Objects Without Losing the Useful Details

JavaScript Basics: Inspect Objects Without Losing the Useful Details

October 24, 2026

A debugging log can hide the field you need or print hundreds of unhelpful entries. Node.js inspect() gives you explicit control over how an object is presented. These examples adjust one part of the display at a time while checking that the underlying data stays intact.

These three independent examples were executed on Linux with Node.js v24.19.0. Use Node.js 24 for this tutorial; only that installed version was tested. They use built-in modules and assertions, with no package installation. They make no network requests and leave no data files behind. The output below is the observed output.

Prepare a scratch directory

You need Bash, Node.js on your PATH, a text editor, and the mktemp, rm, and rmdir utilities. Keep the same terminal open and save each named file as UTF-8 in the new directory. The .mjs extension selects an ES module.

node --version
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

The tested runtime prints:

v24.19.0

1. Choose how far to expand nested objects

Save this as inspect-nested-depth.mjs:

import assert from 'node:assert/strict';
import { inspect } from 'node:util';

const record = { project: { name: 'build', owner: { team: 'tools' } } };
const options = { colors: false, breakLength: Infinity, compact: true };
const shallow = inspect(record, { ...options, depth: 1 });
const expanded = inspect(record, { ...options, depth: 2 });

assert.ok(shallow.includes('owner: [Object]'));
assert.ok(expanded.includes("team: 'tools'"));
assert.equal(record.project.owner.team, 'tools');
console.log(`shallow: ${shallow}`);
console.log(`expanded: ${expanded}`);

Run it:

node inspect-nested-depth.mjs

Output:

shallow: { project: { name: 'build', owner: [Object] } }
expanded: { project: { name: 'build', owner: { team: 'tools' } } }

The shallow view confirms that an owner exists; the expanded view reveals its team. Set depth for the question you are investigating rather than expanding everything by default. The inspect options also control colors and line wrapping. This example disables colors so redirected output contains no terminal color escapes.

2. Limit long values and sort displayed keys

Save this as inspect-compact-preview.mjs:

import assert from 'node:assert/strict';
import { inspect } from 'node:util';

const report = { rows: [11, 22, 33, 44], label: 'weekly-summary', active: true };
const preview = inspect(report, {
  colors: false,
  sorted: true,
  maxArrayLength: 2,
  maxStringLength: 6,
  breakLength: Infinity,
  compact: true,
});

assert.ok(preview.includes('... 2 more items'));
assert.ok(preview.indexOf('active:') < preview.indexOf('label:'));
assert.deepEqual(Object.keys(report), ['rows', 'label', 'active']);
assert.equal(report.label, 'weekly-summary');
assert.equal(report.rows.length, 4);
console.log(preview);
console.log('original values unchanged');

Run it:

node inspect-compact-preview.mjs

Output:

{ active: true, label: 'weekly'... 8 more characters, rows: [ 11, 22, ... 2 more items ] }
original values unchanged

The preview keeps the beginning of each long value and signals that more remains. Sorting affects the presentation, not the insertion order verified by Object.keys(). The assertions check the complete original string and array, so display truncation cannot be mistaken for deleting data.

3. Keep getters unevaluated until you choose otherwise

Save this as inspect-getter-side-effects.mjs:

import assert from 'node:assert/strict';
import { inspect } from 'node:util';

let reads = 0;
const record = {
  get total() {
    reads += 1;
    return 42;
  },
};
const options = { colors: false, customInspect: false };
const passive = inspect(record, { ...options, getters: false });
assert.equal(reads, 0);
console.log(`without evaluation: ${passive}`);
console.log(`getter calls: ${reads}`);

const evaluated = inspect(record, { ...options, getters: true });
assert.equal(reads, 1);
assert.ok(evaluated.includes('42'));
console.log(`with evaluation: ${evaluated}`);
console.log(`getter calls: ${reads}`);

Run it:

node inspect-getter-side-effects.mjs

Output:

without evaluation: { total: [Getter] }
getter calls: 0
with evaluation: { total: [Getter: 42] }
getter calls: 1

The counter makes the side effect visible: inspecting with getters enabled executes application code. Keeping getters false avoids that evaluation in this example. customInspect: false additionally skips custom inspection hooks. These options are debugging controls, not a sandbox for arbitrary hostile objects.

Practical limits

inspect() is synchronous and intended for debugging. Node explicitly warns that its output format can change, so do not parse it or use it as a storage format. The printed punctuation here is specific to the tested runtime. Truncation is not redaction: select safe fields before logging rather than assuming a length limit will hide secrets. Use structured JSON logging for a defined machine-readable record.

Clean up

In the same terminal, remove only the three named source files, return to your starting directory, and remove the now-empty scratch directory:

rm -- inspect-nested-depth.mjs inspect-compact-preview.mjs inspect-getter-side-effects.mjs
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

Acknowledgements

This post was created with assistance from AI.

Last updated on