#Shallow vs deep copy
- A shallow copy creates a new top-level object, but nested objects are still shared with the original.
- A deep copy recursively copies everything, so nothing is shared.
The distinction exists because of how objects are stored. A variable or property never contains an object — it contains a reference to one (see Types and dynamic typing). So when you copy an object's properties, a property holding a primitive copies the value itself, but a property holding a nested object copies only the reference. The copy ends up pointing at the very same nested object. "Shallow" means exactly that: one level is new, everything below is shared.
const original = { toy: "Car", smallBox: { toy: "Doll" } };
const shallow = { ...original };
shallow.toy = "Ball"; // fine — top level is separate
shallow.smallBox.toy = "Robot"; // ⚠ changes original too!
original.toy; // "Car"
original.smallBox.toy; // "Robot"originalis one object with two properties:toyholds the string"Car", andsmallBoxholds a reference to a second object,{ toy: "Doll" }.{ ...original }creates a new outer object and copies each property across:toygets its own"Car", andsmallBoxgets a copy of the reference — soshallow.smallBox === original.smallBoxistrue.shallow.toy = "Ball"changes a property on the new outer object only.original.toystays"Car".shallow.smallBox.toy = "Robot"first followsshallow.smallBoxto the shared inner object, then changes itstoyfrom"Doll" → "Robot". There is only one inner object, sooriginal.smallBox.toynow reads"Robot"too.- This is the bug pattern to recognise: code that "copies" an object and then edits something nested inside the copy is editing the original as well.
Think of a shallow copy as a new box with the same inner boxes inside; a deep copy builds new inner boxes too.
const deep = structuredClone(original);
deep.smallBox.toy = "Plane";
original.smallBox.toy; // "Robot" — unaffectedstructuredClone(original)walks the whole structure and creates a new outer object and a newsmallBoxobject, sodeep.smallBox !== original.smallBox.deep.smallBox.toy = "Plane"changes the copy's own inner box.original.smallBox.toyis still"Robot"(the value left by the previous example) — nothing is shared any more.- The trade-off: a deep copy costs time and memory in proportion to the size of the whole structure, whereas a shallow copy costs only one level. That's why most real code uses shallow copies deliberately and copies just the parts it changes (see React).