JSON vs clone transports
WebSocket and the WebExtension family are JSON transports; custom transports can opt in with isJson: true. Everything else uses structured clone + transferables. This page details exactly what changes in JSON mode; for the transport catalogue see transports, and for opting a custom channel into JSON mode see custom transports.
Preserved on JSON via boxes
Section titled “Preserved on JSON via boxes”These all still work over a text-only channel: undefined, NaN/±Infinity, Date, BigInt, Map/Set, TypedArrays and ArrayBuffer (as base64), Error subclasses, Symbol, and every live type (functions, promises, async iterables, readable/writable streams, ports, AbortSignal, Request/Response).
Live values ride synthetic EventChannel ports instead of transferred MessagePorts: fully functional, but wire-routed, so they die with the connection. See lifecycle for what survives connection death.
Degrades or unavailable on JSON
Section titled “Degrades or unavailable on JSON”transfer()becomes a copy; the box is markeddegradedand skipped by the transfer-list walker.- The structured-clone pass-through families are clone-only:
RegExp,FormData,File/FileList,ImageData,DataView, DOM geometry types,CryptoKey,FileSystemHandle, … (clonable) andImageBitmap,OffscreenCanvas,VideoFrame,MediaStreamTrack, … (transferable). TheCapabletype-level check excludes them on JSON transports, so misuse fails at compile time rather than silently coercing. SharedArrayBufferis clone-only.
Unclonables fail on both kinds
Section titled “Unclonables fail on both kinds”On both kinds of transport, values nothing can handle (e.g. WeakMap) coerce to {} at runtime via the unclonable catch-all and are rejected at the type level by Capable; see the TypeScript reference. The full per-type matrix for both transport kinds is in supported types.