Guide

Guida ai Dati Statici e all’Oggetto $workflow in n8n

La maggior parte dei workflow vive di “dati che passano” tra i nodi: arrivano, vengono usati, poi spariscono. Ma spesso serve qualcosa di più: un piccolo stato che sopravvive tra un’esecuzione e l’altra, contatori, cursori di paginazione, mapping che non vuoi riscaricare ogni volta. Qui entra in gioco $workflow n8n e i Dati Statici del workflow: un meccanismo leggero per memorizzare configurazioni e micro‑stati direttamente nell’automazione, senza installare database esterni. In questa guida pratica vedremo cosa sono i dati statici del workflow n8n, come usarli in sicurezza, quando preferirli (e quando no), e come comporli con le variabili di espressione n8n ($json, $node, $env) per routing, naming e logging. Troverai esempi reali (cursore API, contatori, feature flags), consigli su idempotenza e concorrenza esecuzioni n8n, e un mini‑framework per crescere senza introdurre complessità. Se vuoi migliorare produttività e affidabilità dei tuoi flussi da marketer tecnico, questa è la base per portare governance e controllo nelle tue automazioni.

📚 Nuovo a n8n? Parti dalla guida completa: cos’è n8n e come funziona.

[IMG: panoramica dello scope dati in n8n: item → node → workflow static data]

Dati transitori vs stato persistito: quando serve e perché

Nel modello a item di n8n, i dati viaggiano da un nodo all’altro sotto forma di array di oggetti JSON ($json in espressioni n8n). Questi dati sono transitori: cambiano ad ogni esecuzione. A volte però serve uno “zainetto” persistente:

  • Configurazioni persistenti workflow: piccole preferenze (formati, mapping campi) che non vuoi hardcodare nel nodo.
  • Cursore di paginazione API: l’ultimo next_page token processato; al prossimo run riparti da lì.
  • Contatori di esecuzione: quante volte hai pubblicato oggi, per canale/campagna.
  • Cache leggera in automazioni: lookup/mapping in n8n a bassa volatilità (es. ID canale → nome pubblico).
  • Idempotenza nei workflow: memorizza checksum o riferimenti di eventi già processati.

Differenze chiave

  • Dati transitori: vivono nel run corrente (item, output nodi). Perfetti per trasformazioni veloci.
  • Dati statici del workflow n8n: persistono tra run; dimensione piccola; ideali per piano di controllo e micro‑config.

Best practice n8n espressioni: separa il dato “business” (item) dal “controllo” (static data). E tieni l’input del workflow come sorgente della verità: lo stato persistito serve a ricordare “dove sei arrivato”, non a sostituire la fonte.

[IMG: tabella comparativa “transitorio vs statico” con esempi]

L’oggetto $workflow di n8n: metadati, scope e riferimenti utili

$workflow n8n è accessibile nelle espressioni e ti dà metadati dell’automazione utili per naming, logging e routing. Esempi tipici:

  • Esempi in espressioni
  • Nome workflow: {{$workflow.name}}
  • ID workflow: {{$workflow.id}}
  • Naming file/log: report*{{$workflow.name}}*{{ $now }}.csv
  • Tagging run: {{$workflow.id}}-{{ $env.ENVIRONMENT }}
  • Differenze con $node e $json in espressioni n8n
  • $json: il dato dell’item corrente (per esempio {{$json.email}}).
  • $node[“Nome Nodo”].json.campo: accedi a un output specifico di un nodo precedente.
  • $env: leggi variabili d’ambiente (token, ID foglio, URL API).
  • $workflow: metadati del flusso per scopi cross‑cutting (naming, logging, branch per ambiente).

Scope dei dati in n8n

  • Scope globale del workflow: utile per etichette e contesto.
  • Scope del singolo nodo: usalo per riferimenti puntuali o default di quel nodo.

Esempi d’uso concreti

  • Routing per ambiente: If → {{$env.ENVIRONMENT}} == ‘prod’ → percorsi diversi di notifica.
  • Logging coerente: Append log row → fields: workflowid: {{$workflow.id}}, executionts: {{ $now }}.
  • Convenzioni di naming file/output: s3://bucket/{{ $env.BRAND }}/{{$workflow.name}}/{{ $now }}.json

Insight: usare $workflow negli output e nelle notifiche rende ogni run auto‑documentata e facile da investigare.

[IMG: screenshot placeholder con espressioni $workflow, $env, $json nel pannello proprietà]

Pattern di persistenza: cursori, contatori, mapping e feature flags

Quando memorizzare

  • Cursore di paginazione API: salva next_page token ad ogni run concluso con successo. Se fallisce, non aggiornare (eviti “buchi”).
  • Contatori di esecuzione: mantieni un contatore giornaliero per canale (utile per rate limiting applicativo).
  • Cache di configurazioni/mapping: es. canale_id → nome; TTL logico (ricarica ogni N run/ore).
  • Feature flags e versioning di flusso: interruttori per attivare/disattivare path senza modificare i nodi.

Esempio (pseudo‑JS in un Code node) per cursore API e contatore giornaliero:

// Pseudocodice per illustrare il pattern
// Lettura stato persistito (es. oggetto staticData globale)
const state = staticData.global || {}; // fallback oggetto vuoto
const today = new Date().toISOString().slice(0,10);

// Cursore API
const previousCursor = state.nextCursor || null;
// ... chiama API usando previousCursor ...
const nextCursor = $json.apiResponse?.next_cursor || null;
if (nextCursor) state.nextCursor = nextCursor;

// Contatori giornalieri per canale
state.counts = state.counts || {};
const channel = $json.channel || 'unknown';
state.counts[today] = state.counts[today] || {};
state.counts[today][channel] = (state.counts[today][channel] || 0) + 1;

// Salvataggio
staticData.global = state;

return [{ json: { previousCursor, nextCursor, processed: 1 } }];

Note operative (ciclo di vita, limiti)

  • Mantieni lo stato piccolo (stringhe, numeri, array/dict compatti).
  • In caso di migrazione/cleanup, prevedi reset dei dati statici (svuota l’oggetto o definisci una chiave di versione, es. state.version = 2).
  • Evita dataset grandi o lookup complessi: passa a un DB/KV store esterno.

[IMG: diagramma con “API → process → update cursor → next run resumes”]

Concorrenza e idempotenza: evitare race e duplicazioni

Concorrenza esecuzioni n8n

  • Se il workflow può avviarsi in parallelo (Cron sovrapposti, trigger multipli), rischi race condition sullo stato.
  • Pattern di lock leggero: salva un lock con timestamp ed execution marker; se un’altra run lo vede “attivo”, si mette in attesa o esce.

Idempotenza nei workflow

  • Prima di eseguire side effects (email, inserimenti), verifica in uno “storico” che l’ID sorgente non sia già stato processato.
  • Usa contatori/checksum nello stato per saltare azioni ripetute.
  • Gestisci retry con backoff e segna esiti (success/fail) con motivazione per safe reprocessing.

Esempio (pseudo‑JS) per lock e idempotenza:

const state = staticData.global || {};
const now = Date.now();
const lockTTLms = 5 * 60 * 1000; // 5 minuti

// Lock
if (state.lock && (now - state.lock.ts) < lockTTLms) {
  // lock attivo: abbandona o riprova più tardi
  return [{ json: { skipped: true, reason: 'locked' } }];
}

// Acquisisci lock
state.lock = { ts: now };
staticData.global = state;

// ... esegui lavoro idempotente ...
// es: se vedi source_event_id in state.processed, salta
state.processed = state.processed || {};
const evt = $json.source_event_id;
if (evt && state.processed[evt]) {
  return [{ json: { skipped: true, reason: 'already_processed' } }];
}

// Esegui side effect e marca come processato
// ... side effect ...
state.processed[evt] = true;
delete state.lock;
staticData.global = state;

return [{ json: { ok: true } }];

Suggerimenti

  • Se hai traffico elevato o necessità di garanzie forti, usa un KV store/DB con lock atomico (redis, postgres) e conserva lo stato di idempotenza lì.
  • Per piccoli team e throughput basso, il lock leggero in dati statici è sufficiente.

[IMG: timeline con due esecuzioni concorrenti e lock che evita conflitti]

Espressioni e $workflow in pratica: routing, naming, logging

Esempi pratici (copiabili):

  • Routing per canale/ambiente
  • If → Condizione: {{$env.ENVIRONMENT}} === ‘prod’ && {{$json.channel}} === ‘linkedin’
  • True branch: pubblica; False: logga come “dry‑run”.
  • Naming coerente per export
  • File Name: {{ $env.BRAND }}{{ $workflow.name }}{{ new Date().toISOString().slice(0,10) }}.csv
  • Logging strutturato (Append Row su Google Sheets o DB)
  • Fields: workflowid: {{$workflow.id}}, runts: {{ $now }}, item_id: {{$json.id}}, outcome: {{$json.status}}

Pattern per lookup/mapping in n8n

  • Se mapping statico è piccolo (es. codice → canale), conservalo nei dati statici e leggilo con un Code node in avvio run.
  • Aggiorna il mapping in modo controllato (flag di versione; se cambia, ricalcola al primo run).

Differenze pratiche tra $workflow, $node, $json e $env (sintesi)

  • $json: payload dell’item corrente.
  • $node: referenzia output di altri nodi (utile per join/merge).
  • $env: configurazioni segrete/ambienti (non committare nel workflow).
  • $workflow: metadati; usalo per contesto, naming, tag.

[IMG: pannello proprietà con esempi di espressioni interpolate nei campi]

Quando NON usare i Dati Statici e alternative scalabili

Evita i Dati Statici se:

  • Dataset grandi o query complesse: hai bisogno di filtri, ordinamenti, ricerche—usa un DB/warehouse o un KV store.
  • Team concurrency: più utenti/istanze modificano lo stato; rischi conflitti. Meglio un archivio centralizzato con lock transazionali.
  • Compliance/audit: serve storico delle modifiche e tracciabilità nel tempo—usa storage versionato.

Alternative consigliate

  • DB esterno (Postgres/MySQL): per cursori per sorgente, idempotenza forte, audit.
  • KV store (Redis): rate limiting, lock, cache a TTL.
  • File/Blob (S3/Drive): export periodici e snapshot dello stato di controllo.
  • API di configurazione: mantieni le config in un servizio dedicato e leggile nel workflow.

Pulizia/reset dei Dati Statici

  • Prevedi un percorso “Reset”: un Code node che azzera lo stato o incrementa una version key, forzando rigenerazione al prossimo run.
  • Migrazioni tra versioni e ambienti: serializza lo stato in JSON, salvalo temporaneamente, poi re‑importalo con trasformazioni minime.

[IMG: decision tree “static data vs DB/KV” con criteri di scelta]

Esempio end‑to‑end: ingest API paginata con cursore, dedupe e log

Obiettivo: chiamare un’API paginata, ripartire dall’ultimo cursore, deduplicare item per id, e loggare risultato.

Blueprint

  1. Trigger: Cron ogni 15 minuti.

  2. Carica stato: Code node legge state (cursore, processed ids).

  3. Chiamata API: HTTP Request → usa previousCursor.

  4. Process: dedupe su item_id contro state.processed.

  5. Persisti: aggiorna cursore se la chiamata è ok, marca nuovi id processati.

  6. Log: Append su Sheet/DB con conteggi.

Pseudo‑JS (Code node “State Manager”):

const state = staticData.global || { version: 1, processed: {}, nextCursor: null };
const prev = state.nextCursor || null;
return [{ json: { state, prevCursor: prev } }];

Chiamata API (HTTP Request) usa {{ $json.prevCursor }} in query; a valle:

const state = $json.state;
const items = $json.apiResponse?.data || [];
const out = [];
for (const it of items) {
  if (!state.processed[it.id]) {
    out.push(it);
    state.processed[it.id] = true;
  }
}
state.nextCursor = $json.apiResponse?.next_cursor || state.nextCursor;
staticData.global = state;
return out.map(i => ({ json: i }));

Questo pattern offre persistenza stato automazioni n8n senza DB, con deduplica semplice e ripartenza affidabile.

[IMG: workflow canvas con nodi: Cron → Code(State) → HTTP → Code(Process) → Sheets(DB)]

Quick Takeaways

  • Usa $workflow per metadati e contesto: naming coerente, logging e routing per ambiente.
  • I Dati Statici sono perfetti per cursori, contatori, mapping piccoli e feature flags.
  • Mantieni lo stato leggero e versionato; per dataset grandi passa a DB/KV esterni.
  • Gestisci concorrenza con lock leggeri e idempotenza su side effects.
  • Combina $json, $node, $env e $workflow per espressioni potenti e leggibili.
  • Prevedi reset/migrazione dello stato e monitora con log strutturati.

Conclusione

Portare stabilità e

Articoli correlati

Vuoi automazioni AI su misura per la tua azienda?
Scopri la consulenza →

Partiamo da un processo che oggi vi costa ore

Su WhatsApp risponde una persona, di solito in giornata. Se preferisci scrivere con calma, c’è il modulo qui sotto.

Scrivici su WhatsApp

Raccontaci cosa vuoi automatizzare

Ti rispondiamo noi, di solito in giornata.

Raccontaci cosa vi fa perdere tempo

Due righe bastano. Vi diciamo se si automatizza, come, e quanto costa. Se non conviene, lo diciamo.