structuredClone()
Creates a deep copy of a value, preserving Map, Set, Date, typed arrays and circular references.
structuredClone(value)
structuredClone(value, options)- Added in JavaScript Baseline March 2022 (WHATWG HTML; Node.js 17)
Parameters
| Parameter | Type | Description |
|---|---|---|
$value | any | The object to be cloned. It must be a structured-cloneable type. |
$optionsoptional | object= undefined | An options object. |
$options.transferoptional | Transferable[]= undefined | An array of transferable objects to be moved rather than copied. Transferred objects are detached from the original and attached to the clone. |
Return value
anyA deep copy of the given value, with circular references and supported built-in types preserved.
Errors
Throws a DataCloneError DOMException if any part of the input is not serializable — functions, class instances' prototypes, DOM nodes, WeakMap, Symbol and Error subclass details are among the values it rejects or flattens.
Changelog
- PHP Node.js 17Exposed as a global, matching browsers. Earlier Node versions have no structuredClone.
structuredClone() runs the structured clone algorithm — the same machinery that moves data between a page and a worker — as a plain function call. It gives you a genuine deep copy with none of the compromises of the JSON.parse(JSON.stringify(x)) trick.
What it handles that JSON does not
Map,Set,Date,RegExp,ArrayBuffer, typed arrays andBigInt.- Circular and shared references — an object referenced twice in the source is one object in the clone, not two.
undefinedvalues and array holes, which JSON drops or nulls.
What it refuses
Functions, methods, getters, Symbol, WeakMap and DOM nodes cause a DataCloneError. Class instances survive but arrive as plain objects: the prototype is not carried across, so instanceof fails and methods are gone. Property descriptors are flattened too — a getter becomes its evaluated value, and writable: false is not preserved.
When to reach for it
Snapshotting mutable state before an operation you might need to undo, isolating a caller's object from later mutation, or building an independent copy for a worker. For an object graph you own that is only plain data, it is both faster and more faithful than serialising through JSON.
Example
When to use it
- Snapshot application state before a risky mutation so you can restore it.
- Defensively copy an options object a caller passed in, so later mutations cannot reach you.
- Duplicate a graph containing Maps, Sets and Dates that JSON round-tripping would destroy.
Frequently asked questions
Why does structuredClone throw DataCloneError?
Because some part of the value is not structured-cloneable — most often a function, a method on a plain object, a Symbol, a WeakMap, or a DOM node. Strip or replace those properties before cloning, or copy the data-only subtree instead.
Is structuredClone better than JSON.parse(JSON.stringify(obj))?
Yes for most cases: it preserves Date, Map, Set, RegExp, typed arrays, BigInt, undefined and circular references, all of which the JSON trick destroys or crashes on. The JSON approach is only preferable when you specifically want a JSON-shaped result.
Does structuredClone copy class instances and their methods?
No — it copies own enumerable data properties into a plain object and drops the prototype, so methods and getters are gone and instanceof returns false. Rehydrate with a constructor call or a fromJSON-style factory if you need the class back.
More examples
Against the JSON round trip
The clone keeps a real Date, a real Set, the undefined key and the BigInt. The JSON round trip turns the Date into a string, the Set into {}, drops the undefined key entirely, and would throw outright on the BigInt.
const src = {
when: new Date(0),
set: new Set([1, 2]),
nothing: undefined,
big: 10n,
};
console.log(structuredClone(src));
console.log(JSON.parse(JSON.stringify({ ...src, big: 0 })));Prototypes and getters are lost
Only own enumerable data properties survive. The accessor `length` is not an own property so it vanishes, `toString` falls back to Object.prototype's, and the instance is no longer a Point.
class Point {
constructor(x, y) { this.x = x; this.y = y; }
get length() { return Math.hypot(this.x, this.y); }
toString() { return `(${this.x}, ${this.y})`; }
}
const p = new Point(3, 4);
const c = structuredClone(p);
console.log(p instanceof Point, c instanceof Point); // true false
console.log(c); // { x: 3, y: 4 }
console.log(typeof c.toString, c.length); // function undefined
console.log(Object.getPrototypeOf(c) === Object.prototype); // trueTransferring a buffer instead of copying it
With `transfer`, the underlying ArrayBuffer is moved rather than duplicated: the clone owns the memory and the original view is left detached with zero length. Useful for large binary payloads, destructive for anything you still need.
const data = new Uint8Array(1024);
data[0] = 42;
const moved = structuredClone(data, { transfer: [data.buffer] });
console.log(moved[0], moved.byteLength); // 42 1024
console.log(data.byteLength); // 0 — original detached
console.log(data.buffer.detached); // true
Discussion