Lesson 0001 · ~10 minutes

When structured clone fits (and when it doesn’t)

One skill: place structured clone on the copy / serialize spectrum and pick it only when the hard problem is a faithful deep copy of structured values — not a JSON document, not a shallow spread, not class revival.

Win for this lesson

After the quiz, you can defend “JSON / structuredClone / shallow / transfer / custom” in a design review — and stop treating JSON.parse(JSON.stringify(x)) as a deep clone.

1. You already met the algorithm

In Workers lesson 3, structured clone was the default message tax: postMessage copies; transfer moves ownership; functions and DOM nodes throw DataCloneError. BroadcastChannel uses the same algorithm with no transfer list. IndexedDB stores values that survive that algorithm.

This track owns the algorithm as a first-class tool: what it is, when to call structuredClone() yourself, and when a different copy tool is the honest choice.

The HTML Standard calls the serialize + deserialize pair structured cloning. Most APIs split those steps (store now, restore later; send here, receive there). structuredClone() is the exception: both steps, same realm, one call.

2. The problem structured clone solves

JavaScript assignment copies a reference. Surma (web.dev) splits the rest into two jobs people confuse:

You need a deep copy when two pieces of code must not accidentally share state: a form draft vs the store, a worker payload you will keep mutating, a History entry that must not alias live UI state.

Until 2022 you faked that with JSON round-trip or a library. The platform now exposes the same algorithm it already used internally:

const snapshot = structuredClone(draft);

MDN: baseline widely available (Chrome 98+, Firefox 94+, Safari 15.4+). In 2026 that is the default — not a polyfill conversation.

3. Not JSON, and not a class copier

Two confusions that cause bad design reviews:

Don’t trust every 2021 “limitation” list

Surma’s article is the right decision primary, but two details aged: JSON usually silently loses Map/Set/Date rather than throwing, and Error is now cloneable per MDN. When in doubt, WHATWG + current MDN win.

4. Copy / serialize spectrum

Shallow copy

New outer object; nested refs stay shared. Right when you only replace top-level fields.

JSON round-trip

You need a JSON document (HTTP, file, log). Accept or design around loss. Not a deep-clone substitute.

Structured clone

Faithful deep copy of structured data: cycles, Dates, Maps, buffers, many Web types. Explicit: structuredClone(). Implicit: postMessage, BC, IDB, History.

Transfer

Move ownership of a transferable (you already know this from workers). Sender is detached.

Custom serializer

Methods, class identity, schema versions, stable cross-language wire. Structured clone will not revive your Invoice class.

Default rule (steal this)

If the hard part is “this same-realm value must become an independent nested copy”, call structuredClone(). If a platform API will already clone (worker message, IDB put, pushState), pass data through — don’t double-clone. If the hard part is “a server or file must parse JSON”, use JSON and design for what it drops. If you only need a new outer object, shallow. If you need methods or a versioned domain type, custom serializer. Large binary ownership → transfer.

Signal Leans structured clone Leans away
Job Independent deep copy of structured data JSON document, shared nested refs, or class revival
Who clones You call structuredClone(), or an API already does You structuredClone and then postMessage the copy for no reason
Types Dates, Maps, Sets, cycles, buffers, Blobs Functions, DOM nodes, live class instances
Failure mode Throws DataCloneError (loud) JSON silent drop / stringify TypeError
Classic fits Detach a draft from a store; snapshot before mutate; History state; IDB / worker payloads REST body, protobuf file, “clone this Vue/React proxy with methods”
FE integration difficulty (honest preview)

structuredClone(x) is one line. What bites later: reactive proxies (Vue/MobX) that throw DataCloneError, clone cost on huge graphs (Workers lesson 3), transfer detachment surprises, and thinking a clone preserved methods. Type matrix and transfer next. Today: pick the right row on the spectrum.

5. Practice — pick the copy tool

Choose the best default. Equal-length options so formatting doesn’t hint. Feedback is immediate.

Scenario A

A modal must edit a nested editor draft. The store object, including nested arrays and a Date, must stay untouched.

Scenario B

POST settings to your REST API. The server only accepts application/json.

Scenario C

You copy a user to set name. Nested prefs should stay the same object so both sides see pref updates.

Scenario D

Persist a domain Invoice class (methods, private fields, schema version) to a file other services must read for years.

Scenario E

A worker should take ownership of a 16MB ArrayBuffer of pixels. Main thread must not keep using those bytes.

6. What to remember

Ask your teacher Anything fuzzy — Vue/React proxies, a “clone” helper on your team, a DataCloneError you’ve seen — ask in chat. Follow-up questions are part of the method, not a distraction.

Primary source (read next)

Surma — Deep-copying in JavaScript using structuredClone. Best primary for this lesson’s job split (shallow vs JSON hack vs platform deep copy). Then skim MDN — Structured clone algorithm for the type list you’ll own next lesson. Remember the two dated claims in the 2021 article (JSON rarely throws on Map/Date; Error now clones).