What is the most efficient way to deep clone an object in JavaScript?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In modern JavaScript, the best general-purpose answer is usually structuredClone(...). It is built into current runtimes, handles many more data types than the old JSON trick, and avoids a lot of bugs that appear when people try to write their own recursive deep-clone logic.
What “Deep Clone” Actually Means
A deep clone creates a new object graph, not just a new top-level object. That means nested arrays and nested objects are copied instead of shared.
For example, this is only a shallow copy:
That prints "Grace" because the nested user object was still shared.
A deep clone should avoid that by duplicating the nested structure as well.
Use structuredClone First
If the runtime supports it, structuredClone is the cleanest built-in choice:
This creates an independent copy of the nested data.
structuredClone is stronger than JSON.parse(JSON.stringify(...)) because it supports more kinds of values and can handle circular references:
That works, while the JSON approach would fail on the circular reference.
When JSON Cloning Is Still Acceptable
The old JSON pattern still appears everywhere:
It is simple, and for plain JSON-compatible data it can be fine. But it has important limits:
- it drops functions
- it loses
undefined - it converts
Dateobjects to strings - it cannot handle
Map,Set, or circular references
So the JSON trick is not “wrong.” It is just narrower than many examples admit. Use it only when the data is truly plain JSON data and you want a quick compatibility-oriented solution.
Know What structuredClone Does Not Clone
structuredClone is not magic. It is great for structured data, but some values are not cloneable in the way people expect.
For example, functions are not deep-cloned as executable copies of behavior. DOM-related objects and special class instances may also behave differently than a plain-object copy.
That means deep cloning is often the wrong operation when your data includes:
- class instances with methods
- open sockets or live resources
- framework-managed objects
- closures or functions
In those cases, a dedicated conversion function or domain-specific copy method is usually more correct than a generic deep clone.
Performance Depends on Data Shape
The “most efficient” method depends on what you are cloning.
For ordinary structured data in modern environments:
- '
structuredCloneis usually the best default' - JSON cloning can be fast enough for plain data but loses type information
- custom recursive cloners often become bug farms unless you truly need special behavior
The biggest performance mistake is usually not choosing the wrong cloning function. It is cloning far more data than the application actually needs.
Often the real solution is:
- clone only the branch you need
- use immutable update patterns
- avoid cloning large trees on every render or request
If your application deep-clones huge objects repeatedly in a hot path, the design may need revision more than the cloning function does.
A Safe Fallback Strategy
If you need broad runtime support, you can use structuredClone when available and fall back to JSON for plain data:
This is a practical fallback only when you know the non-structuredClone case will receive JSON-safe data.
When a Library Still Makes Sense
If the project already uses a utility library with a tested deep-clone function, that can still be fine. Libraries can help when:
- runtime support is mixed
- the application already depends on that utility package
- the team wants consistent behavior across environments
But do not add a dependency automatically if a built-in solution already covers the real use case.
Common Pitfalls
The most common pitfall is using object spread or Object.assign and assuming the result is a deep clone. Those only copy the first level.
Another mistake is using the JSON trick on data containing dates, maps, sets, circular references, or undefined, then wondering why values disappeared or changed type.
A third issue is deep cloning framework objects or class instances that were never meant to be copied generically. Structured data is a better target for cloning than behavior-rich objects.
Finally, developers often ask for the “fastest deep clone” when the bigger problem is unnecessary cloning. Reducing clone frequency can matter more than micro-optimizing the method.
Summary
- In modern JavaScript,
structuredCloneis usually the best default deep-clone option. - It handles nested data and circular references better than the JSON trick.
- '
JSON.parse(JSON.stringify(...))is only safe for plain JSON-compatible data.' - Shallow copies such as spread syntax do not clone nested objects.
- If deep cloning is a hot-path bottleneck, reconsider the data-flow design as well as the cloning method.

