Vuoi creare workflow flessibili che si adattano ai dati in arrivo, all’ambiente o all’utente, senza duplicare decine di flussi? Le espressioni dinamiche nodi n8n ti permettono di trasformare qualsiasi campo in un valore calcolato al volo: URL, header, body JSON, parametri di paginazione, perfino la scelta dei rami logici. In questa guida pratica impari a usare il motore di espressioni di n8n con un approccio operativo: dal contesto dati disponibile ($json, $node, $items(), $now) alla sintassi essenziale ({{ }}, dot/bracket, ?. e ??), fino alle configurazioni reali dei nodi chiave come HTTP Request, Webhook Trigger, Respond To Webhook, Item Lists e Split In Batches. Vedrai pattern solidi per centralizzare configurazioni con un sub‑workflow, passare da test a produzione senza toccare i nodi, generare header Authorization dinamici, costruire body JSON “a prova di errore” e gestire paginazione/loop. Chiudiamo con debug, error handling e sicurezza (evitare segreti in chiaro e log sensibili). Obiettivo: ridurre la manutenzione, accelerare i rilasci e aumentare l’affidabilità dei flussi con espressioni in n8n per parametri dei nodi dove serve davvero.
Motore e contesto dati disponibili
Le espressioni vivono tra doppie graffe: {{ … }}. Puoi referenziare:
- $json: i campi dell’item corrente. Esempi: {{ $json.email }}, {{ $json.parent.child }}.
- $node[“NomeNodo”].json[“campo”]: output JSON di un nodo precedente, utile per comporre richieste complesse a valle.
- $items(): per riferirsi a più items quando lavori con array.
- $now: timestamp corrente, utile per tracciare eventi o generare correlationId.
Esempi rapidi:
- Impostare un timestamp su un campo: {{ $now }}
- Propagare un ID ottenuto da un nodo “Lookup”: {{ $node[“Lookup ID”].json[“id”] }}
- Se un campo potrebbe mancare, usa operatori sicuri (vedi sezione sintassi) per evitare errori in fase di esecuzione.
Questo contesto rende le espressioni dinamiche nodi n8n potenti per comporre parametri dipendenti dai dati in transito, mantenendo i workflow DRY e riutilizzabili.
Sintassi e operatori utili: come scrivere espressioni robuste
- Delimitatori: racchiudi ogni espressione tra {{ e }}.
- Notazione: dot (es. $json.user.name) o bracket (es. $json[“user”][“name”]) quando ci sono spazi o caratteri speciali nel nome.
- Optional chaining (?.): evita errori se un campo è assente, es. {{ $node[“A”].json?.profile?.email }}.
- Nullish coalescing (??): imposta default solo se null/undefined, es. {{ $json.amount ?? 0 }}.
- Ternario: {{ condizione ? valoreSeVero : valoreSeFalso }} per switch veloci di URL, header o body.
- Map/filter su array: per adattare liste prima di inviarle a un’API, combinando con Item Lists per manipolazioni più comode a livello di nodo.
Regole d’oro:
- Usa ?? anziché || per default numerici o stringhe vuote (0 e “” sono valori validi).
- Spezza le trasformazioni: meglio 2–3 campi calcolati chiari che una singola espressione illeggibile.
URL, query string e body nell’HTTP Request
Il nodo “HTTP Request” è il coltellino svizzero per integrare API. Puoi rendere dinamici URL, query e body senza passare da un Code node.
Esempio configurazione di GET con query dinamiche:
{
"name": "Search Products",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"parameters": {
"url": "={{ `https://api.example.com/v1/products?q=${$json.query ?? ''}&limit=${$json.limit ?? 25}` }}",
"method": "GET",
"responseFormat": "json"
}
}
POST con body JSON dinamico:
{
"name": "Create Customer",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"parameters": {
"url": "https://api.example.com/v1/customers",
"method": "POST",
"responseFormat": "json",
"jsonParameters": true,
"bodyParametersJson": "={{ { email: $json.email?.trim?.(), name: $json.name ?? 'Sconosciuto', tags: $node[\"Segment Builder\"].json.tags ?? [] } }}"
}
}
Suggerimenti:
- Mantieni responseFormat: “json” quando il server restituisce JSON per ottenere parsing automatico.
- Valida preventivamente i campi “obbligatori” con un If node se possibile, per evitare 4xx evitabili.
Header e token Authorization dinamici
Quando le credenziali non possono essere selezionate dinamicamente, costruisci l’header Authorization con un’espressione che pesca il token da un nodo precedente o da configurazioni centralizzate.
Esempio:
{
"name": "Partner API Call",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"parameters": {
"url": "={{ `${$json.baseUrl}/v2/orders` }}",
"method": "POST",
"responseFormat": "json",
"jsonParameters": true,
"bodyParametersJson": "={{ $json.order }}",
"headerParametersUi": {
"parameter": [
{
"name": "Authorization",
"value": "={{ `Bearer ${$node[\"Get Env\"].json[\"token\"]}` }}"
}
]
}
}
}
Vantaggi:
- Nessun duplicato di workflow per test/prod: basta cambiare il token a monte.
- Puoi aggiornare il token con un sub‑workflow “Get Env” a inizio esecuzione.
Nota: Evita di concatenare segreti in altre stringhe se poi finiscono in log; limita l’uso delle espressioni per segreti ai soli campi “header” o “credentials”.
Campi dinamici nei nodi di integrazione (Telegram, Slack, CRM)
La maggior parte dei nodi nativi accetta espressioni nei campi chiave. Esempi d’uso:
- Messaggi con dati personalizzati: {{
Ciao ${$json.firstName}, il tuo ordine ${$json.orderId} è pronto!}} - Allegati/URL presi da un nodo “Upload”: {{ $node[“Upload File”].json[“url”] }}
- Filtri o ID record da step precedenti: {{ $node[“Search Lead”].json[“id”] }}
Linee guida:
- Usa $node[“NomeNodo”] per evitare ambiguità quando il flusso si ramifica.
- Normalizza una volta (con Set) e riutilizza i campi calcolati in più nodi, per leggibilità.
Sub‑workflow “Get Env”: centralizzare baseUrl, token e chiavi
Per ridurre duplicazioni: metti baseUrl, token e altre chiavi in un workflow separato e richiamalo con “Execute Workflow”.
Pattern:
- Caller: workflow principale con un nodo “Execute Workflow” che chiama “Get Env”.
- Callee: workflow “Get Env” (attivato da “Workflow Trigger”) che restituisce un item con { baseUrl, token, … }.
Nel workflow principale, referenzia i valori così:
- {{ $node[“Get Env”].json[“baseUrl”] }}
- {{ $node[“Get Env”].json[“token”] }}
Benefici:
- Un solo punto di verità per URL/chiavi/parametri.
- Rotazione o cambio ambiente senza toccare i nodi di business.
Variabili d’ambiente e credenziali: quando usare cosa
- Variabili d’ambiente: utili per impostazioni non sensibili (feature flag, nome ambiente) o segreti gestiti dall’infrastruttura. Referenziale con un nodo iniziale che le estrae e le espone nel JSON per poi usarle nelle espressioni a valle.
- Credenziali: preferisci le “Credentials” per integrare servizi esterni; tieni i segreti fuori dalle espressioni quando possibile e usali direttamente nel nodo che li supporta. Se hai bisogno di token dinamici (rotanti), portali in un sub‑workflow e passa l’header Authorization come visto sopra.
Best practice:
- Mantieni segregazione dev/stage/prod ed evita di “iniettare” segreti in log o output di nodi non necessari.
Switch test/prod con Set e If: routing sicuro degli endpoint
Gestione ambienti senza duplicare workflow:
1) Con un Set iniziale, definisci l’ambiente corrente:
- env: {{ $json.env ?? ‘prod’ }}
2) Seleziona baseUrl con ternario:
- {{ $json.env === ‘test’ ? ‘https://api.sandbox.example.com’ : ‘https://api.example.com’ }}
3) Oppure usa un If node per instradare a rami diversi e restituire baseUrl specifiche nell’output del ramo “True/False”.
Infine, nel nodo HTTP Request, punta sempre a {{ $json.baseUrl }}. Così, cambiando un solo flag a monte, reindirizzi tutto il flusso.
Referenziare altri nodi: pattern robusti
- Campo singolo da un nodo upstream:
- {{ $node[“Fetch Token”].json[“access_token”] }}
- Ricostruire un oggetto con dati di più nodi:
- {{ { user: $node[“Get User”].json, order: $node[“Get Order”].json } }}
- Evita nomi di nodi ambigui o duplicati; nomina i nodi in modo descrittivo (“Get Env”, “Search Lead”, “Build Body”) per rendere le espressioni autoesplicative.
Default e pulizia dati: evitare errori e payload “sporchi”
- Default numeri/stringhe:
- {{ $json.amount ?? 0 }}
- {{ ($json.name ?? ”).trim() }}
- Normalizzare array:
- {{ ($json.tags ?? []).map(t => t.trim()).filter(Boolean) }}
- Attenzione a || con numeri: 0 || 10 restituisce 10 (spesso non desiderato). Usa ?? per distinguere “assenza” da “valore valido”.
Pulizia prima di HTTP Request:
- Esegui un Set per calcolare i campi “puliti” e poi usa quei campi nell’HTTP Request per ridurre sorprese.
Paginazione e loop: Split In Batches e parametri dinamici
Per liste lunghe, controlla il ritmo con “Split In Batches” ed evita di colpire le API con burst.
Esempio:
{
"name": "Batch Loop",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 1,
"parameters": {
"batchSize": 10
}
}
Pattern:
- A monte, crea una lista di ID/record (Item Lists “splitIntoItems” se parti da un array).
- Applica “Batch Loop”; i nodi successivi useranno i 10 items correnti.
- Al termine, ricollega l’uscita “No Items” per chiudere il loop o attivare step finali.
Parametri dinamici per page/limit nell’HTTP Request:
- URL con {{
...?page=${$json.page ?? 1}&limit=${$json.limit ?? 100}}} - Aggiorna page a ogni iterazione usando un Set o un Code leggero tra i batch.
Anteprima e debug delle espressioni
Per ridurre i tentativi:
- Usa l’anteprima dei campi con espressioni direttamente nel nodo per vedere il valore calcolato sugli items correnti.
- Esegui run parziali (Run Once) e fissa dati di test a monte per rendere predittivo il risultato a valle.
- Nei casi complessi, crea un Set “debug” temporaneo che salvi i valori intermedi in campi appositi, poi rimuovilo prima del rilascio.
Gestione errori: If, Error Trigger e logging mirato
- If node: intercetta stati non validi (campi obbligatori mancanti, status API non 2xx) e instrada su rami di recupero.
- Error Trigger: workflow dedicato per centralizzare errori; includi nel payload di notifica il nome workflow, nodeName, correlationId e messaggio.
- In nodi critici, mantieni responseFormat: “json” dove possibile e valida i campi attesi prima di proseguire.
Consiglio operativo:
- In caso di API instabili, aggiungi retry/backoff a livello di flusso (batching e ramificazioni) e invia a canale di revisione manuale gli item “irrecuperabili”.
Performance e leggibilità: quando usare Function/Code node
Le espressioni bastano per il 90% dei casi. Passa a Function/Code node quando:
- la trasformazione è lunga/annidata e riduce la leggibilità;
- riusi la stessa logica complessa in più punti (incapsula in un sub‑workflow);
- devi manipolare set di dati ampi con operazioni non comode in espressione.
Regola pratica: se un’espressione supera 2–3 linee e include logica condizionale multipla, spostala in un Code node e restituisci i campi già “pronti all’uso”.
Selezione credenziali non dinamica: workaround con header/token e sub‑workflow
Alcuni nodi non permettono di cambiare “Credentials” a runtime. Usa questo approccio:
1) Sub‑workflow “Get Env” → restituisce { baseUrl, token }.
2) HTTP Request con header Authorization dinamico:
{
"headerParametersUi": {
"parameter": [
{ "name": "Authorization", "value": "={{ `Bearer ${$node[\"Get Env\"].json[\"token\"]}` }}" }
]
}
}
3) URL dinamico su {{ $node[“Get Env”].json[“baseUrl”] }}.
Così gestisci ambienti e rotazioni di token senza modificare manualmente le credenziali nei nodi.
Sicurezza: best practice nelle espressioni
- Non inserire segreti in chiaro in campi non necessari; usa header/cred che non vengono loggati in output.
- Evita di concatenare token in stringhe che potresti “stampare” in log/risposte API.
- Separa ambienti e limita permessi: i workflow di test non devono accedere a segreti di produzione.
- Pulisci i dati prima di loggarli: rimuovi PII non necessaria e maschera ID sensibili quando fai debug.
Esempio end‑to‑end: endpoint dinamico con token e body variabili
1) Webhook Trigger (ack immediato per evitare timeout):
{
"path": "incoming-action",
"methods": ["POST"],
"responseMode": "onReceived",
"responseData": { "statusCode": 200, "body": "Webhook received successfully" }
}
2) “Get Env” (Execute Workflow) → output: { baseUrl, token }
3) Normalizzazione (Set):
- action: {{ ($json.action ?? ”).trim() }}
- payload: {{ $json.payload ?? {} }}
4) HTTP Request
{
"name": "Call Partner Action",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"parameters": {
"url": "={{ `${$node[\"Get Env\"].json[\"baseUrl\"]}/actions/${$json.action}` }}",
"method": "POST",
"responseFormat": "json",
"jsonParameters": true,
"bodyParametersJson": "={{ $json.payload }}",
"headerParametersUi": {
"parameter": [
{ "name": "Authorization", "value": "={{ `Bearer ${$node[\"Get Env\"].json[\"token\"]}` }}" }
]
}
}
}
5) Validazione risposta (If): controlla status e campi attesi
6) Respond To Webhook (solo se flusso sincrono): restituisci { ok, data } con status 200 o errore coerente.
Questo pattern dimostra come referenziare dati da nodi precedenti n8n, costruire body JSON dinamico e impostare un header Authorization dinamico in automazioni.
Quick Takeaways
- Le espressioni rendono dinamici URL, header e body senza codice: usa {{ … }}, $json, $node[…] e $now.
- Usa operatori ?. e ?? per evitare crash e gestire default puliti; preferisci ternari per switch test/prod.
- Centralizza baseUrl/token in un sub‑workflow “Get Env” e referenzia con $node[…] per ridurre duplicazioni.
- HTTP Request: imposta responseFormat: “json”, jsonParameters: true e bodyParametersJson con oggetti costruiti via espressioni.
- Paginazione/loop: Item Lists “splitIntoItems” + Split In Batches con batchSize adeguato.
- Gestione errori: If per condizioni previste e Error Trigger per allarmi centralizzati.
- Sicurezza: non loggare segreti, usa header/cred dedicati e separa ambienti.
Conclusione
Le espressioni dinamiche nodi n8n sono la scorciatoia più efficace per trasformare workflow statici in servizi adattivi. Con pochi pattern — contesto ($json, $node, $now), sintassi solida (?., ??, ternario), HTTP Request con header/body dinamici e un sub‑workflow per configurazioni — puoi passare da ambienti test a produzione, integrare partner diversi, gestire paginazione/loop e validazioni, il tutto senza moltiplicare i flussi. Per i marketers, significa più velocità nel lanciare automazioni, meno copia‑incolla e maggiore affidabilità. Inizia da un flusso che oggi modifichi spesso a mano (URL, token, parametri): estrai le variabili in “Get Env”, rimpiazza i campi con espressioni e aggiungi If/validazioni dove serve. Dopo poche iterazioni vedrai workflow più brevi, chiari e facili da mantenere, pronti a scalare con nuove campagne e integrazioni.
FAQ
-
Come referenzio un valore da un nodo precedente?
-
Usa {{ $node[“NomeNodo”].json[“campo”] }} per accedere in modo esplicito all’output di un nodo upstream e usarlo in URL, header o body.
-
Come imposto un header Authorization dinamico?
-
In “headerParametersUi”, aggiungi un parametro “Authorization” con valore {{
Bearer ${$node["Get Env"].json["token"]}}} o una fonte simile. -
Posso costruire un body JSON complesso senza Code node?
-
Sì. Imposta “jsonParameters”: true e “bodyParametersJson” a un oggetto costruito con espressioni, es. {{ { email: $json.email, tags: $node[“Tags”].json.list } }}.
-
Come gestisco paginazione e liste grandi?
-
Con Item Lists (operazione “splitIntoItems”) per esplodere array in items singoli e “Split In Batches” con “batchSize” per controllare il ritmo delle chiamate.
-
Come evito di duplicare workflow per test e produzione?
-
Centralizza baseUrl e token in un sub‑workflow “Get Env” richiamato con “Execute Workflow” e usa ternari/If per gestire routing tra sandbox e produzione.
Hai messo in pratica uno di questi pattern? Racconta quale configurazione dinamica ti ha fatto risparmiare più tempo e condividi questo articolo con il tuo team: quale parametro trasformerai in espressione questa settimana?
Scopri la consulenza →

