How to JSON.stringify() Circular and Complex Objects
Standard JSON.stringify() fails on circular references and handles complex types poorly. These techniques handle the cases that stringify cannot.
Handling Circular References
A circular reference occurs when object A contains a reference to object B, which references back to A (directly or through a chain). JSON.stringify throws TypeError for circular structures because JSON cannot represent them.
The most reliable fix is a replacer that tracks seen objects: const seen = new WeakSet(); JSON.stringify(obj, (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) return "[Circular]"; seen.add(value); } return value; }). This replaces circular references with a placeholder string.
Serializing Maps and Sets
JSON.stringify produces {} for Map objects and [] for Set objects — neither preserves the content. To serialize a Map, convert it to an array of pairs: JSON.stringify([...myMap]). To restore it: new Map(JSON.parse(serialized)). For Sets: JSON.stringify([...mySet]) and new Set(JSON.parse(serialized)).
For objects that contain nested Maps and Sets, use a replacer function that converts them recursively: if (value instanceof Map) return { __type: "Map", data: [...value] }. The corresponding reviver in JSON.parse rebuilds the Map from this representation.
Serializing Class Instances
Class instances serialize to plain objects containing their own enumerable properties. Methods and prototype properties are excluded. For controlled serialization, implement toJSON() on the class: toJSON() { return { type: "User", id: this.id, name: this.name }; }. JSON.stringify calls this automatically.
For deserializing back to class instances, the reviver parameter of JSON.parse can reconstruct them: JSON.parse(json, (key, value) => { if (value && value.type === "User") return new User(value); return value; }).
Using Libraries for Complex Serialization
The flatted library provides drop-in replacements for JSON.stringify and JSON.parse that handle circular structures by encoding them as references. The serialize-javascript library handles functions, RegExp, Date, and Infinity in addition to circular references.
For debugging purposes, util.inspect() in Node.js produces a detailed string representation of any JavaScript value, including circular references and non-serializable types. It is not valid JSON but is extremely useful for logging complex objects.
Try JSON Stringify Online Free Online
No sign-up required. 100% client-side — your data never leaves your browser.
Open JSON Stringify Onlinearrow_forwardFrequently Asked Questions
Is there a standard way to represent circular JSON?
No. The JSON specification does not support circular structures. Each library that handles circular references uses its own encoding scheme, so the output of flatted, for example, cannot be parsed by standard JSON.parse.
Can I serialize DOM nodes with JSON.stringify?
No. DOM nodes are not plain objects and contain circular references (parentNode, ownerDocument, etc.). JSON.stringify throws on them. Serialize only the data you care about, not the DOM node itself.
How does structuredClone() handle types that JSON cannot serialize?
structuredClone() handles Dates (preserved as Date), Maps, Sets, ArrayBuffers, and more. It throws for functions and DOM nodes. It handles circular references by preserving the reference structure in the clone.