O Structured Clone no Node.js permite criar cópias profundas de muitos valores JavaScript sem recorrer ao padrão limitado de JSON.stringify() e JSON.parse(). A função global structuredClone() preserva tipos como Date, Map, Set, RegExp, ArrayBuffer e TypedArray, além de lidar com referências circulares.
O mesmo algoritmo aparece em MessageChannel, BroadcastChannel, Worker Threads e outras APIs da plataforma Web. Ele é útil para isolar estado, preparar mensagens entre threads, criar snapshots de objetos e transferir buffers sem cópia quando uma transfer list é permitida.
Neste guia, você aprenderá a clonar objetos, trabalhar com tipos especiais, referências circulares, propriedades, transferências, erros, desempenho, segurança e diferenças em relação a JSON e cópias rasas.
O que é structuredClone()?
structuredClone() é uma função padronizada da plataforma Web implementada pelo Node.js. A documentação oficial de structuredClone no Node.js descreve a função global. O guia de structuredClone na MDN apresenta tipos suportados e transferência.
Para comunicação entre threads, consulte MessageChannel no Node.js e Worker Threads no Node.js. Para dados binários, veja Buffer no Node.js.
Clone básico
const original = {
user: {
name: 'Ana',
roles: ['admin', 'editor']
}
};
const copy = structuredClone(original);
copy.user.name = 'Beatriz';
console.log(original.user.name);O objeto aninhado é copiado. Alterações no clone não afetam o original.
Cópia rasa não é suficiente
const shallow = { ...original };
shallow.user.name = 'Carlos';O spread copia apenas o primeiro nível. shallow.user continua apontando para o mesmo objeto interno.
Date
const original = {
createdAt: new Date()
};
const copy = structuredClone(original);
console.log(copy.createdAt instanceof Date);Ao contrário de JSON, Date permanece um objeto Date.
Map
const original = new Map([
['theme', 'dark'],
['language', 'pt-BR']
]);
const copy = structuredClone(original);O resultado continua sendo Map, com chaves e valores clonados.
Set
const original = new Set(['node', 'javascript']);
const copy = structuredClone(original);Set também é preservado.
RegExp
const pattern = /node\.js/gi;
const copy = structuredClone(pattern);A expressão e as flags são preservadas. Estado específico, como lastIndex, deve ser testado conforme a especificação e versão.
ArrayBuffer
const source = new Uint8Array([1, 2, 3]);
const copy = structuredClone(source);
copy[0] = 9;
console.log(source[0]);Sem transferência, os bytes são copiados para memória separada.
Referências circulares
const original = { name: 'root' };
original.self = original;
const copy = structuredClone(original);
console.log(copy.self === copy);JSON.stringify lança erro em estruturas circulares, enquanto structuredClone preserva o ciclo.
Referências repetidas
const shared = { value: 1 };
const original = {
first: shared,
second: shared
};
const copy = structuredClone(original);
console.log(copy.first === copy.second);A relação interna entre referências é preservada dentro do clone.
Transferindo ArrayBuffer
const buffer = new ArrayBuffer(1024 * 1024);
const copy = structuredClone(
{ buffer },
{ transfer: [buffer] }
);Com transferência, a memória é movida em vez de copiada. O ArrayBuffer original fica destacado.
Buffer destacado
console.log(buffer.byteLength);Após a transferência, o tamanho pode se tornar zero e views antigas deixam de ser utilizáveis. Não transfira algo que ainda será usado.
Transferência versus cópia
- Cópia: origem e clone mantêm bytes independentes.
- Transferência: propriedade da memória passa ao clone.
Transferência reduz CPU e pico de memória em buffers grandes.
Buffer do Node.js
Buffer é uma subclasse de Uint8Array, mas pode compartilhar um pool interno. Não transfira cegamente o ArrayBuffer subjacente de um Buffer pequeno.
const dedicated = Uint8Array.from(buffer).buffer;Uma cópia dedicada evita transferir memória pertencente a outros Buffers.
Tipos que não podem ser clonados
Entre valores normalmente incompatíveis estão:
- funções;
- WeakMap e WeakSet;
- alguns objetos nativos com recursos externos;
- símbolos como valores independentes;
- sockets, streams tradicionais e handles.
A tentativa lança DataCloneError ou erro equivalente.
Funções
structuredClone({
handler() {}
});Métodos representam comportamento, não dados serializáveis. Envie um identificador e selecione a função em uma allowlist no destino.
Instâncias de classes
class User {
greet() {
return 'Olá';
}
}
const copy = structuredClone(new User());O clone pode não preservar o protótipo personalizado e métodos da classe. Trate structuredClone como clonagem de dados, não de comportamento.
Propriedades não enumeráveis
Descritores, getters, setters e atributos podem não ser preservados como em uma cópia de metaprogramação. Consulte a especificação e teste objetos especiais.
Getters
Clonar objetos com getters pode avaliar valores durante a leitura conforme o comportamento do algoritmo. Evite efeitos colaterais em propriedades destinadas a transporte.
Erros
Objetos Error possuem suporte que evoluiu ao longo das versões. Nome e mensagem costumam ser preservados; propriedades customizadas devem ser testadas.
structuredClone versus JSON
JSON possui limitações:
- Date vira string;
- Map e Set viram objetos vazios;
- BigInt lança erro;
- undefined é removido;
- NaN e Infinity são alterados;
- ciclos lançam erro;
- ArrayBuffer não é preservado.
Use JSON quando precisa de formato textual interoperável. Use structuredClone para cópia interna.
BigInt
const copy = structuredClone({
value: 9007199254740993n
});BigInt é preservado pelo algoritmo, ao contrário do JSON padrão.
undefined, NaN e Infinity
const copy = structuredClone({
missing: undefined,
invalid: NaN,
infinite: Infinity
});Esses valores são mantidos.
Snapshot de configuração
function getConfigurationSnapshot() {
return structuredClone(currentConfiguration);
}O consumidor recebe uma cópia e não altera o estado interno do módulo.
Estado imutável
StructuredClone não congela o resultado. Use Object.freeze() ou uma estratégia de imutabilidade se o clone não deve ser modificado.
Mensagens entre workers
Worker Threads e MessagePort usam clonagem estruturada. Entender o algoritmo ajuda a prever quais payloads funcionam e quanto custam.
BroadcastChannel
Enviar um objeto grande por BroadcastChannel no Node.js pode clonar dados para vários receptores. Prefira eventos compactos.
Desempenho
O custo cresce com tamanho, profundidade e quantidade de referências. Clonar um objeto de centenas de megabytes pode bloquear a thread e duplicar memória.
Benchmark
const start = performance.now();
const copy = structuredClone(value);
const duration = performance.now() - start;Meça com dados reais e monitore RSS. Consulte Performance Hooks no Node.js.
Limite de tamanho
if (estimatedBytes > MAX_CLONE_BYTES) {
throw new Error('Objeto grande demais');
}Estimar tamanho de um grafo JavaScript não é simples. A melhor defesa é limitar os dados antes de construí-los.
Clonagem em caminhos críticos
Não clone toda a configuração ou cache em cada requisição. Crie snapshots apenas quando necessário ou use estruturas imutáveis compartilhadas na mesma thread.
Segurança
Clonar entrada não torna o conteúdo confiável. O clone ainda precisa de validação antes de ser usado em SQL, caminhos, comandos ou regras de autorização.
Prototype pollution
StructuredClone cria dados separados, mas não substitui allowlist de propriedades. Ao mesclar o resultado em configurações, selecione campos conhecidos.
Recursos externos
Conexões de banco, sockets e streams não devem ser clonados. Passe identificadores ou crie recursos dentro do destino.
Testes
Cubra:
- objeto aninhado;
- referência circular;
- Map e Set;
- Date e RegExp;
- BigInt;
- ArrayBuffer copiado;
- ArrayBuffer transferido;
- função rejeitada;
- classe personalizada;
- objeto grande.
Use o Node Test Runner.
Erros comuns
- Esperar métodos de classe: protótipos customizados podem ser perdidos.
- Transferir e continuar usando: o buffer original fica destacado.
- Clonar objetos gigantes: CPU e memória aumentam.
- Usar como serialização: o resultado não é texto persistente.
- Confiar no clone: dados continuam não validados.
- Transferir pool de Buffer: memória compartilhada pode ser afetada.
- Clonar por requisição: latência cresce sem necessidade.
Boas práticas
- Use para dados, não comportamento.
- Transfira buffers grandes.
- Não reutilize buffers transferidos.
- Limite tamanho.
- Meça custo.
- Valide o resultado.
- Evite caminhos críticos.
- Teste classes e erros.
- Use JSON para interoperabilidade externa.
- Prefira mensagens compactas.
Conclusão
O Structured Clone no Node.js cria cópias profundas de muitos tipos JavaScript, preserva referências circulares e pode transferir ArrayBuffers sem cópia.
Ele resolve limitações do JSON em operações internas, mas não preserva todo comportamento de classes nem transforma dados em conteúdo confiável. Com limites, validação e transferências conscientes, structuredClone é uma ferramenta útil para snapshots e comunicação entre threads sem compartilhamento acidental de estado.



