Hai già creato qualche flusso, ma ti serve più controllo sulla forma dei dati? Con il nodo code n8n puoi modellare, aggregare e validare i payload in modo preciso, lì dove i nodi no‑code non bastano. In questa guida operativa andiamo oltre le basi: vedrai quando ha senso superare i nodi standard, come scegliere tra esecuzione per item e per tutti gli item, come leggere input/contesto e restituire output corretti, come progettare uno schema stabile per il downstream e implementare pattern avanzati (flatten/unflatten, groupBy, join/lookup, deduplicazione). Tratteremo anche performance (chunking, batching), differenze pratiche tra JavaScript e Python, considerazioni su moduli esterni in ambienti self‑hosted e Cloud, e un approccio solido a debug e gestione errori nel Code node. L’obiettivo: padroneggiare la trasformazione dati in n8n con snippet pronti all’uso e linee guida che rendono i tuoi workflow più affidabili, veloci e manutenibili.
[IMG: Editor con nodo “Code” selezionato e menu “Run Once For Each Item / Run Once For All Items” visibile]
Quando superare i nodi no‑code (e perché il Code è la scelta giusta)
I nodi no‑code coprono l’80% dei casi (HTTP Request, Set, IF, Merge, Item Lists, Split In Batches). Ma in alcuni scenari il Code node di n8n è la scorciatoia più pulita:
- Data shaping non coperto: rinomina massiva di campi, conversioni di tipi, calcoli custom, regole condizionali complesse.
- Normalizzazioni multi‑fonte: uniformare diversi payload API a uno schema comune prima di un Merge.
- Filtri/ordinamenti/aggregazioni complessi: preferisci un “punto unico” di verità con codice chiaro anziché proliferare di IF/Switch.
Principio guida:
- Parti dai nodi standard (meno codice = meno debito tecnico).
- Inserisci il Code quando hai un “collo di bottiglia” di trasformazione: di solito 20‑60 righe di JS bastano per risolvere in modo espressivo.
Limitazioni da ricordare:
- Il Code non fa I/O di rete o file system: per chiamate esterne usa “HTTP Request” e passa i risultati al Code.
- Mantieni lo scope del Code “puro” sui dati: più testabile, meno side‑effect.
Risultato: workflow più leggibili, dove il nodo code n8n svolge un ruolo mirato e documentato, senza sostituire ciò che i nodi nativi già fanno bene.
Esecuzione per item vs per tutti gli item: pattern, trade‑off e insidie
Il Code node supporta due modalità chiave.
1) Run Once For Each Item
- Processa un item alla volta.
- Ideale per mapping di campi, calcoli puntuali, validazioni locali.
- Output atteso: un singolo item (oggetto con chiave json).
Esempio (per‑item, mapping + calcolo):
// Mode: Run Once For Each Item
const r = $json;
return {
json: {
id: r.id,
title: String(r.title || r.name || '').trim(),
amount: Number(r.qty || 0) * Number(r.unitPrice || 0),
createdAt: r.createdAt || r.created_at || null,
}
};
2) Run Once For All Items
- Processa tutti gli item insieme con $input.all().
- Perfetto per filtri globali, ordinamenti, dedup, groupBy, aggregazioni.
- Output atteso: un array di item (return items) oppure un singolo item aggregato ({ json: {…} }).
Esempio (all‑items, filtro + sort + limit):
// Mode: Run Once For All Items
const rows = $input.all().map(i => i.json);
const filtered = rows.filter(r => r.status === 'published');
filtered.sort((a, b) => new Date(b.publishedAt) - new Date(a.publishedAt));
const top = filtered.slice(0, 50);
return top.map(j => ({ json: j }));
Trade‑off pratici:
- Per‑item preserva la cardinalità 1:1 (facile da ragionare).
- All‑items è più flessibile ma richiede attenzione al formato di ritorno. Se filtri, restituisci solo gli item che restano (“return top.map(…)”).
Insidia tipica: restituire il formato sbagliato. Ricorda:
- Per‑item: return { json: {…} }
- All‑items: return [{ json: {…} }, …] oppure return items;
Input, contesto e output coerente: item linking e struttura degli item
Struttura degli item
- Ogni messaggio è un item: { json: { … }, binary?: { … } }.
- I nodi scambiano array di item: anche se c’è un solo elemento, è un array di length 1.
Accesso ai dati (built‑in)
- $json: il JSON del corrente item (in per‑item).
- $input.all(): tutti gli item in ingresso (in all‑items).
- $node[“NomeNodo”].json: leggi il json di un nodo precedente per disambiguare fork.
- $items(): riferimento a più item in contesti particolari.
Esempio (all‑items, arricchire gli item con un campo di provenienza):
const items = $input.all();
const enriched = items.map(it => {
const j = it.json;
return { json: { ...j, _sourceNode: $node["HTTP Request"].name || "unknown" } };
});
return enriched;
Item linking: unire dataset
- Usa il nodo “Merge” (ad esempio “Merge By Key”) per allineare stream diversi sulla stessa chiave (es. id cliente).
- Nel Code, preparati a ricevere campi combinati e a gestire conflitti di nomi (prefissi o rinomina).
Output coerente
- Mantieni i nomi dei campi stabili e “case‑sensitive”.
- Preserva gli identificatori chiave (id, guid) per tracciabilità.
- Quando fai aggregazioni, valuta se restituire:
- un array di item (downstream “per‑record”),
- un singolo item aggregato (downstream “riassunto”).
[IMG: Pannello “Input/Output” del nodo Code con array di item e campi json evidenziati]
Normalizzazione dello schema: flatten/unflatten, mapping e default sicuri
Progettare uno schema stabile
- Definisci i tipi per campo (string, number, boolean, date ISO) e rispetta la scelta in tutto il flusso.
- Segna i campi opzionali e fornisci default sicuri (stringa vuota, 0, null).
Flatten JSON e unflatten
- Utile per esporti tabellari (CSV/Sheets) o per semplificare mapping.
Esempio (per‑item, flatten profondo):
function flatten(obj, prefix = '', out = {}) {
for (const [k, v] of Object.entries(obj || {})) {
const key = prefix ? `${prefix}.${k}` : k;
if (v && typeof v === 'object' && !Array.isArray(v)) {
flatten(v, key, out);
} else {
out[key] = v;
}
}
return out;
}
const f = flatten($json);
return { json: f };
Rinomina massiva e mapping enum
// Per-item: rinomina campi e mappa enum in valori standard
const j = $json;
const statusMap = { active: 'ACTIVE', pending: 'PENDING', disabled: 'DISABLED' };
return {
json: {
id: j.id || j._id,
email: String(j.email || '').toLowerCase().trim(),
status: statusMap[j.status] || 'UNKNOWN',
amount: Number(j.amount ?? 0),
createdAt: j.createdAt || j.created_at || null,
}
};
Default sicuri e null‑safety
- Usa coalescenza: j.field ?? default per distinguere tra null/undefined e 0/false validi.
- Pulisci stringhe con trim(), normalizza maiuscole/minuscole, formatta numeri e date coerentemente.
Benefici: downstream prevedibile, meno condizioni speciali, integrazione più fluida con nodi come “Spreadsheet File” o “Google Sheets”.
Aggregazioni avanzate, groupBy, join/lookup e deduplicazione
GroupBy e aggregazioni in n8n
// All-items: somma vendite per categoria
const rows = $input.all().map(i => i.json);
const agg = {};
for (const r of rows) {
const k = r.category || 'Uncategorized';
agg[k] = (agg[k] || 0) + Number(r.amount || 0);
}
const out = Object.entries(agg).map(([category, total]) => ({ json: { category, total } }));
return out;
Finestre temporali e pivot leggeri
- Filtra per data (es. ultimi 30 giorni), poi aggrega.
- Crea piccole “pivot” (es. conteggi per stato) restituendo un oggetto riassunto in un singolo item.
Join/lookup tra dataset
- Preferisci il nodo “Merge” con “Merge By Key” quando possibile.
- In Code, fai lookup con Map/oggetto indicizzato:
// All-items: join sinistro tra arrA e arrB per key=id
const A = $input.all().map(i => i.json); // stream A
const B = $node["Normalize B"].json.rows; // es. passato da nodo precedente
const idx = new Map(B.map(b => [b.id, b]));
const joined = A.map(a => ({ ...a, match: idx.get(a.id) || null }));
return joined.map(j => ({ json: j }));
Deduplicazione record n8n (per chiave)
// All-items: dedup per email
const inRows = $input.all().map(i => i.json);
const seen = new Set();
const deduped = [];
for (const r of inRows) {
const key = String(r.email || '').toLowerCase().trim();
if (!key || seen.has(key)) continue;
seen.add(key);
deduped.push(r);
}
return deduped.map(r => ({ json: r }));
Risultato: dataset compatti, coerenti e pronti per esportazione o analisi, con logiche di business incapsulate in pochi snippet.
Performance, grandi volumi e scelte runtime (JS/Python, moduli esterni)
Performance del Code node
- Complessità: preferisci passate lineari (O(n)), evita nidificazioni costose. Per join, indice prima (Map) e poi scorri.
- Chunking/batching: abbina “Split In Batches” per processare gruppi (es. 100/500 item), inserendo attese tra batch se richieste da rate limit a valle.
Pattern batching
- Pre: sorgente produce array grande → “Item Lists” per splittare in item singoli.
- Process: “Split In Batches” → Code/HTTP → “Execute Next Batch”.
- Post: ricomposizione se serve, oppure esportazione diretta.
Scelta tra JavaScript e Python
- JavaScript: default, veloce, integrazione stretta con $json, $input.all(), return items; ottimo per trasformazioni generiche.
- Python: utile per calcoli specifici, ma verifica il supporto runtime; in molti casi JS “vanilla” copre l’esigenza con meno attrito.
Moduli esterni in ambiente self‑hosted e Cloud
- Self‑hosted: puoi avere maggiore controllo su dipendenze e ambienti.
- Cloud: adotta le capacità di base del Code; per librerie complesse preferisci nodi dedicati o sub‑workflow/servizi esterni.
- Regola d’oro: se serve una libreria “pesante”, considera di spostare la logica in un servizio o usare nodi nativi che ottimizzano I/O e retry.
[IMG: Canvas con “Item Lists → Split In Batches → Code → HTTP Request → Execute Next Batch”]
Debug efficace e contratti di schema: prevenire errori prima che succedano
Debug e gestione errori nel Code node
- Log mirati: console.log() con conteggi, chiavi e range; rimuovi i log a fine debug.
- try/catch con messaggi chiari:
try {
const items = $input.all().map(i => i.json);
if (!Array.isArray(items)) throw new Error('Input non array');
// ... trasformazioni
return items.map(j => ({ json: j }));
} catch (e) {
throw new Error(`Code node: ${e.message}`);
}
Contratti di schema
- Documenta input/output attesi del Code: campi, tipi, opzionalità.
- Valida e sanitizza all’ingresso: default, trim, cast dei tipi.
- A valle, usa “IF” per intercettare record invalidi e deviare verso un ramo di correzione o log.
Da JSON annidato a tabella CSV
// Per-item: selezione e ordering campi per export
const j = $json;
const row = {
id: j.id,
email: (j.email || '').toLowerCase(),
country: j.address?.country || '',
total: Number(j.total ?? 0),
createdAt: j.createdAt || null,
};
return { json: row };
Merge eventi con finestra temporale
// All-items: dedup per key + finestra recente
const now = Date.now();
const windowMs = 1000 * 60 * 60 * 24 * 7; // 7 giorni
const rows = $input.all().map(i => i.json).filter(r => {
const t = new Date(r.timestamp || r.createdAt || 0).getTime();
return !isNaN(t) && (now - t) <= windowMs;
});
const seen = new Set();
const out = [];
for (const r of rows) {
const key = r.guid || r.id || r.url;
if (!key || seen.has(key)) continue;
seen.add(key);
out.push(r);
}
return out.map(r => ({ json: r }));
Suggerimenti finali:
- Nomina coerente (snake/camel) e commenti orientati al flusso.
- Snippet riutilizzabili: crea un “catalogo” interno di ricette (flatten, groupBy, join, dedup).
Quick Takeaways
- Scegli la modalità giusta: per‑item per mapping/local, all‑items per filtri/ordinamenti/aggregazioni/dedup.
- Rispetta la struttura: item = { json, binary? }; output coerente con return { json } o return items.
- Normalizza presto: tipi, default, rinomina massiva e, se serve, flatten/unflatten.
- Per join/lookup usa “Merge By Key” o indici in Map; per dedup scegli una chiave stabile (email/id/guid).
- Scala con Item Lists + Split In Batches; riduci complessità con passate lineari e indici.
- Debug disciplinato (log, try/catch) e contratti di schema evitano regressioni e sorprese a valle.
Conclusione
Il nodo code n8n è il perno della trasformazione dati in n8n quando servono controllo e precisione: ti permette di modellare payload eterogenei in uno schema stabile, aggregare e deduplicare con pochi passaggi, e preparare i dati per nodi downstream o esportazioni. Scegliendo con cura tra esecuzione per item e per tutti gli item, rispettando la struttura degli item e i contratti di schema, riduci drasticamente bug e fragilità. Con pattern come flatten/unflatten, groupBy, join/lookup e dedup, affronti i casi avanzati senza appesantire il canvas. E grazie a batching, codice “vanilla” e debug mirato, mantieni performance e manutenibilità anche su volumi crescenti. Per i marketer, questo si traduce in automazioni più affidabili e insight più puliti, con meno tempo speso a “ripulire” i dati e più tempo dedicato a decisioni e risultati. Inizia dagli snippet e dai pattern di questa guida: il tuo prossimo workflow avrà dati più chiari e un downstream più felice.
FAQ
1) Quando conviene passare dal no‑code al Code node di n8n?
Quando devi applicare trasformazioni non coperte dai nodi standard: mapping massivo, normalizzazioni complesse, filtri/ordinamenti avanzati o aggregazioni custom. Mantieni però HTTP/FS nei nodi dedicati.
2) Come scelgo tra esecuzione per item vs tutti gli item?
Usa per‑item per modifiche 1:1 e all‑items per operazioni globali (filtri, sort, dedup, groupBy). Ricorda il formato: per‑item return { json }, all‑items return items.
3) Come implemento una deduplicazione affidabile?
Definisci una chiave stabile (email/id/guid). In all‑items, usa un Set per tracciare le chiavi viste e restituisci solo i record unici. Se necessario, limita a una finestra temporale.
4) Posso fare join/lookup senza scrivere molto codice?
Sì, con il nodo “Merge” e modalità “Merge By Key”. In alternativa, indicizza il dataset secondario in una Map e arricchisci gli item primari in un Code all‑items.
5) Come ottimizzo performance su grandi volumi?
Evita complessità elevate: indicizza prima, scorri poi. Usa “Item Lists” per splittare array e “Split In Batches” per processare chunk, con piccole attese se imposte da rate limit a valle.
Ci dai una mano?
Quale pattern userai per primo nel tuo prossimo flusso: dedup per chiave, join con Merge o normalizzazione con flatten? Se ti è stato utile, condividi questo articolo con il team e raccontaci nei commenti il tuo caso d’uso: arricchiremo la raccolta di snippet per la community!
Scopri la consulenza →

