javascript

How to print a JavaScript object as JSON

In JavaScript, printing an object as JSON usually means producing a JSON text representation that you can log, store, or transmit reliably. Because JavaScript objects can contai...

Mara Ellison
How to print a JavaScript object as JSON

What printing an object as JSON means in practice

In JavaScript, printing an object as JSON usually means producing a JSON text representation that you can log, store, or transmit reliably. Because JavaScript objects can contain methods, undefined, circular references, and host-specific values, a direct conversion can omit or misrepresent data. The canonical approach is JSON.stringify, with optional replacer and space arguments to control filtering and formatting. Understanding how primitives, dates, toJSON, and circular structures behave helps you produce predictable, stable output suitable for debugging, configuration, and interoperability.

Core method: JSON.stringify behavior and signature

The convert and serialize process

JSON.stringify transforms a JavaScript value into a JSON text string. Its signature is JSON.stringify(value, replacer?, space?), where value is the object to serialize, replacer optionally filters and transforms properties, and space controls pretty-print indentation. When serializing plain objects, primitives are copied according to JSON grammar; functions, undefined, and Symbols are omitted in object contexts, and Date serializes to an ISO string via toJSON. Circular references throw, and toJSON can customize output by returning a serializable value.

Basic usage patterns for common cases

  • Compact output: JSON.stringify(obj) produces a minimal one-line JSON string.
  • Indented output: JSON.stringify(obj, null, 2) adds readable two-space indentation.
  • Filtered output: JSON.stringify(obj, ["key1", "key2"]) includes only listed keys.
  • Transforming output: JSON.stringify(obj, (key, value) => ...) can mutate values during serialization.

Handling nested structures and special values

Dates, toJSON, and implicit coercion

When a property value is a Date, toJSON returns an ISO string, ensuring cross-system compatibility. If an object defines toJSON, JSON.stringify calls it and serializes the returned value. Be aware that undefined, functions, and Symbols are dropped in objects; in arrays they become null. Circular references anywhere in the tree cause JSON.stringify to throw, so sanitize or use custom serialization when working with Maps, Sets, DOM nodes, or class instances that may form cycles.

BigInt, Symbol, and non-finite number caveats

JSON does not define BigInt or Symbol; including them in structures leads to omission in standard serialization. Non-finite numbers like Infinity are not valid JSON and may be omitted or coerced to null depending on the environment. Typed arrays and plain arrays serialize naturally, but class instances often require a toJSON method to express state meaningfully. Recognizing these edge cases prevents subtle data loss when printing object graphs to JSON.

Safe pretty-printing and deterministic output

Controlling whitespace and property ordering

Use space for readable logs, commonly 2 or 4 spaces. Note that JSON.stringify does not guarantee property order for non-integer keys across all engines, though modern JavaScript preserves own string-key insertion order for ordinary objects. Avoid relying on ordering for critical interchange, and be explicit when you need stable dumps. For debugging, consistent indentation and sorted keys in the replacer can make diffs easier to review.

Replacer patterns for normalization

  • Normalize dates: Convert Date to ISO string explicitly if you need strict control.
  • Strip sensitive fields: Filter out passwords or tokens in the replacer.
  • Flatten references: Replace functions or Symbols with descriptive placeholders if needed for trace logs.
  • Handle circular references: Use a custom serializer or a library that supports cycles when printing complex domain models.

Alternatives and ecosystem options for robust printing

When standard JSON.stringify is not enough

For complex object graphs with Maps, Sets, functions, or cycles, standard JSON.stringify may be insufficient. Alternatives include libraries such as flatted, json-stringify-safe, or custom traversal serializers that produce lossless representations. In server-side environments, util.inspect can render objects for human logs, though that output is not JSON. Evaluate trade-offs between strict JSON compliance and the convenience of cycle-tolerant formats depending on whether the output is for machine consumption or debugging.

Common pitfalls and verification checklist

To reliably print objects as JSON, validate input shapes, handle toJSON overrides, and test edge cases. Confirm that optional properties, inherited attributes, and prototype methods do not pollute serialization. Ensure numeric values remain within finite range when interoperability is required. Prefer explicit property selection in replacer when schemas are stable, and log at the appropriate indentation level for operator readability. When in doubt, assert round-trip fidelity by parsing the produced string and comparing essential fields.

Quick reference comparison

Use caseRecommended approachNotes
Simple, human-readable logsJSON.stringify(obj, null, 2)Readable indentation; watch for undefined and functions
Minimal transfer payloadJSON.stringify(obj)Compact; removes undefined and functions in objects
Filtered keysJSON.stringify(obj, ["id","name"])Only listed keys included; others omitted
Custom transform or date normalizationJSON.stringify(obj, (key, value) => { ... })Return transformed values; can coerce types
Objects with circular referencesUse a cycle-safe library or sanitize before serializingStandard JSON.stringify throws on cycles
Non-plain objects (Maps, Sets, class instances)Implement toJSON or use a specialized serializerEnsure output meets interoperability expectations

Best practices checklist for production code

  • Prefer JSON.stringify with a deterministic replacer and explicit space for logs.
  • Define toJSON on domain objects to control what gets serialized.
  • Validate and sanitize input to avoid leaking sensitive fields.
  • Handle or avoid circular references; prefer flattening or ID references for state transfer.
  • Test output against expected schemas and verify round-trip when fidelity matters.
  • Document any custom serialization behavior for future maintainers.

Summary and concise takeaways

Printing a JavaScript object as JSON reliably depends on choosing JSON.stringify with appropriate replacer and space arguments, understanding how it treats Dates, toJSON, undefined, functions, Symbols, and circular structures, and using sanitization or alternative serializers when dealing with complex domain models. For logs, pretty-print with a small indentation; for interchange, prefer compact output with explicit fields. Recognizing edge cases and validating output ensures your printed JSON remains accurate, interoperable, and safe across environments.