Before using JSON.stringify() to deep-copy an object, there's something you should know.
One of the common tricks for creating a deep copy in JavaScript has always been:
const copy = JSON.parse(JSON.stringify(object));
It works.
Until your object contains something JSON wasn't designed to handle.
So let's compare:
structuredClone() vs JSON.stringify() for deep copying.
Let's take it one step at a time.
The old trick: JSON.stringify() + JSON.parse()
The idea is simple.
First, convert the object into a JSON string:
JSON.stringify(object)
Then convert it back into a new object:
JSON.parse(...)
You now have a new object with no nested references shared with the original.
The problem?
JSON.stringify() wasn't designed for cloning objects.
It was designed for JSON serialization.
And that difference matters.
For example:
const user = {
name: "Ayman",
createdAt: new Date(),
value: undefined,
};
const copy = JSON.parse(JSON.stringify(user));
After cloning:
-
Datebecomes a string. -
undefinedproperties disappear. - Functions inside objects disappear.
-
MapandSetdon't preserve their contents normally. -
BigIntcan throw an error.
And circular references?
const user = {
name: "Ayman"
};
user.self = user;
JSON.stringify(user);
That throws a TypeError.
JSON simply doesn't have a way to represent that circular reference.
Then we got structuredClone()
Instead of converting the object to a string and parsing it again:
const copy = structuredClone(object);
That's it.
structuredClone() was actually designed for cloning structured data.
It supports many types that the JSON trick doesn't preserve correctly:
DateRegExpMapSetArrayBuffer- Typed Arrays
BlobFile
And remember our circular reference?
const user = {
name: "Ayman"
};
user.self = user;
const copy = structuredClone(user);
console.log(copy.self === copy);
// true
No problem.
The relationship between the references is preserved in the cloned object.
But structuredClone() isn't magic either.
Functions still can't be cloned:
structuredClone({
sayHello() {}
});
// DataCloneError
DOM nodes can't be cloned with it either, and things like property descriptors, getters/setters, prototype chains, and RegExp.lastIndex aren't necessarily preserved.
So it's a much better general-purpose cloning tool.
But it's not a universal "clone literally anything" button.
So which one should you use?
If your actual goal is:
"I need an independent deep copy of this data."
structuredClone() is usually the better tool.
const copy = structuredClone(original);
Especially when your data contains things like Date, Map, Set, or circular references.
But if your goal is actually serialization:
const json = JSON.stringify(data);
Then use JSON.stringify().
For example, when you need JSON to send through an API, store as text, or work with a system that expects JSON.
And yes, the old:
JSON.parse(JSON.stringify(object))
still works for simple JSON-compatible data.
Just remember what you're actually doing.
You're not using a cloning API.
You're serializing the object... then rebuilding it.
This is the third post in Frontend Battles series, where I'll compare popular frontend tools, libraries, and technologies to help you understand their strengths, trade-offs, and when to choose each one.
Top comments (1)