Skip to content
PD
n8n

Data and Expressions in n8n: Items, $json and Why a Node Runs Many Times

How data works in n8n: an array of items rather than an object, $json and node expressions, reaching earlier nodes, nested JSON, merging and splitting branches, and the usual empty-data mistakes.

All articles in the guide n8n · 18

Most problems in n8n are not logic problems, they are data shape problems. Understanding how data flows through a workflow will close more questions than studying any particular node.

Data is an array, not an object

The core model: what passes between nodes is an array of items. Each item is a self-contained piece of data with its own JSON.

From which the main consequence follows: a node runs once per item. Give it 50 items and it makes 50 HTTP requests, sends 50 messages, creates 50 records.

That is the model rather than a bug, but it produces the classic surprises: “why did it send 50 emails instead of one” and “why did the API rate-limit me”. If you need a single run, collapse the items first rather than hoping the node will “understand”.

The inverse is just as common: an API returns one item that contains an array of 50 objects inside. To n8n that is still one item, so the next node runs once. To process them individually, the array has to be split into items.

Expressions

Anywhere a field takes a value, you can supply an expression instead of a constant.

  • $json - the current item’s JSON. A field is read as $json.email, or $json["Field Name"] when the name has spaces.
  • Referencing a node by name - the output of a specific earlier block, not necessarily the immediately preceding one.
  • Built-in values - current time, execution id, workflow data.

A practical tip that saves hours: rename nodes meaningfully as you go. An expression pointing at HTTP Request1 is unreadable a month later and breaks when blocks move. Fetch order reads well and survives refactoring.

Nested JSON

Real APIs return nesting, and this is the second place people trip. The path is dotted: $json.customer.address.city.

The catch is that any link in that chain can be missing. If customer came back empty, reaching for .address.city fails the execution. On data where some fields are optional this is a guaranteed source of intermittent failures - the workflow runs for a week, then a record without an address arrives.

Guard where a field can realistically be absent: check for it before reading, or supply a default. There is no need to wrap everything defensively - only the fields whose absence is plausible.

Branching and merging

Conditions and branching split the flow: some items go one way, some another. The common mistake is forgetting that the second branch also needs handling; the items that went there did not vanish, they simply took a different route.

Merging branches is where surprises are born most often. Two data sets can be combined in several ways: appended, matched on a key, intersected. If a merge produced more items than you expected, the wrong mode is almost always the reason - not n8n “duplicating” anything.

Debug the data, not the diagram

The primary tool is execution history. It shows what entered each node and what left it. Diagnosis nearly always reduces to finding the first node where the data stopped being what you assumed.

The order that works:

  1. Open the execution and walk left to right until you find the first divergence from expectation.
  2. Watch not just values but the item count - a sudden jump or drop is usually the root cause.
  3. Check whether the input is empty. A node that receives zero items does not execute at all - which looks like “the step was skipped” even though it is perfectly logical.

That last point deserves emphasis: an empty result in n8n is rarely an error by itself. It quietly stalls the entire branch below it.

Common traps

  • A number arrived as a string. APIs often return "42", and comparing it to a number gives surprising results.
  • An empty string is not a missing field. Checking for existence and checking for emptiness are different checks.
  • Field name casing. Email and email are different fields, and a classic source of “why is it blank”.
  • Zero items on input. The branch silently does not run, with no error anywhere.

When a workflow behaves inexplicably, start from the hypothesis “the data is not the shape I think” - it is confirmed more often than all other causes combined. What to do once something has actually failed is covered in error handling.

FAQ

Why does a node in n8n run several times?

Because data in n8n is an array of items and a node runs once per item. If the previous node returned 50 records, the next one makes 50 requests. That is the execution model, not a bug: to get a single run, collapse the items into one item first.

How do I reference data from a previous node in n8n?

Use $json for the current item, and reference a specific node by its name for its output. This is exactly why nodes deserve meaningful names: an expression pointing at "HTTP Request1" breaks the first time you rearrange blocks and is unreadable a month later.

More on this topic

Done for you

I will build the automation in n8n or in code

Leads, sheets, CRM and Telegram connected, so nobody moves data by hand again.

from $300 · 3 to 7 days

Similar caseBAS Script License Issuing Automated on MakeA Make scenario that turns one Telegram message into a full licence handover: generated login and password, a licence for the requested term, FingerprintSwitcher Business enabled, and a row written to Google Sheets.

"Thanks to Pavel, the task is done. Always reachable, gave me detailed instructions and a guide, I will come back and I recommend him to everyone."

MarkBorisov · KworkTranslated from Russian