n8n Loop Over Items: Batching and Automatic Looping
How n8n loops through items automatically, how the Loop Over Items node works, and which batch size makes sense for performance and rate limits.
The biggest n8n learning hurdle explained: what items, $json and $node mean and how to map values by drag and drop without code.
Anyone building a workflow in n8n for the first time sooner or later reaches a point where a fixed UI setting is no longer enough: a value needs to come from the previous node, change depending on the input data, or come from a completely different node earlier in the workflow. This is exactly where the biggest learning hurdle begins for many new users, because terms like $json, $node and items suddenly appear, which without explanation look like cryptic code. Yet behind this lies a fairly simple principle, once it is clear how n8n passes data between nodes.
This article explains using concrete examples what an item in n8n really is, how $json and $node relate to each other, and how you map values by drag and drop, without writing a single line of code yourself. It is based on the official n8n documentation on expressions and the internal data structure, as of July 2026.
n8n always passes data between nodes as an array of objects, and each individual element in this array is called an item. According to the n8n documentation on the data structure every item has the fixed form { json: {...} }, where the actual payload data always sits under the key json. An example with two items looks like this:
{ json: { name: "Anna", plz: "18055" } }{ json: { name: "Jonas", plz: "23552" } }Important for understanding: a node in n8n usually processes each item individually and repeats its configured action for each element in the array. If an HTTP Request node receives two items, it sends two requests by default, one per item. Once you have internalized this, you also understand why expressions in n8n always refer to the item currently being processed and not to the entire list.
$json is the most frequently used variable in n8n expressions and represents the json data of the item that the current node is processing. $json is a shorthand for $input.item.json, the input item of the current node. If, for example, you want to output the name from the example above in the next node, you write in a text field:
{{ $json.name }}
n8n replaces this expression at execution time with the actual value of the respective item, so with two items it would be "Anna" once and "Jonas" once. You can reach nested fields using dot notation, for example {{ $json.adresse.plz }}, provided the data is structured accordingly.
As soon as a value should not come from the directly preceding node, but from any other node earlier in the workflow, $json is no longer enough. This is exactly what $node, or its successor $(), is for. In older workflows and tutorials you will often still find the notation $node["Node-Name"].json.feld, this syntax is now considered deprecated. The current form, described in the n8n documentation on referencing previous nodes is:
{{ $('Node-Name').item.json.feld }}
If you want not only the currently linked item, but specifically the first, last, or all items of a particular node, you additionally have $('Node-Name').first(), $('Node-Name').last() and $('Node-Name').all() available. If you find an old expression written with $node in a workflow, it is worth updating it to the $() notation when you get the chance, so that it also continues to work reliably after future n8n updates.
Suppose a workflow starts with a form node called "Kontaktformular", which captures an email address among other things. Three nodes later, in an HTTP Request call to a CRM, you need exactly this address again, even if the nodes in between no longer contain any email data themselves. The expression for this is:
{{ $('Kontaktformular').item.json.email }}
This way, regardless of what the nodes in between have done with the data, you access the original item from the Kontaktformular node directly.
The most convenient way into expressions does not involve typing any code at all. In the input panel of a node, n8n displays the incoming data as a list or table, and each individual field can be dragged directly with the mouse into a parameter field. n8n automatically generates the matching expression from this, for example {{ $json.fruit }}, without you needing to know the syntax yourself. According to the n8n documentation on expressions versus data transformation nodes this method is especially worthwhile when you only want to take over a single value from previous data, because n8n shows directly in the preview which specific value will be used at execution time. For operations such as sorting, merging, or removing duplicates, the documentation instead recommends the ready-made data transformation nodes, because these work without any expression at all and are operated through a guided interface.
{ json: {...} }, otherwise n8n reports an error.Once you have internalized these four points, you have overcome the biggest entry hurdle in n8n and from then on keep control over your own workflows, even without a developer background. Anyone who, despite this, prefers experienced support when building more complex automations will find at NordFlux's n8n automation an implementation with a fixed price and German data sovereignty.
$json is a shorthand for $input.item.json and directly returns the json data of the current item. $input.item, on the other hand, returns the complete item object including a possible binary key, which is why $json in practice is almost always the shorter and more common way when you only want to access normal field values.
$node["Name"].json was the original syntax for referencing data from a specific node, but is now considered deprecated. n8n instead recommends the notation $('Name'), which handles renamings and future version changes more reliably. Old workflows with $node mostly continue to work, but should be updated at the next opportunity.
No, $json always refers only to the item of the directly incoming data stream at the current node. For fields from any other node located earlier in the workflow, you need the notation $('Node-Name').item.json.feldname, as described in the documentation on referencing previous nodes.
No, mostly not. You can drag fields from the input panel directly into a parameter field, n8n automatically generates the matching expression. Typing by hand is worthwhile especially when you want to access data from a more distant node or want to further process the values with methods such as .toUpperCase() or .map().
Then the expression usually returns undefined or an empty value instead of an error, unless you access a field of a nested object that does not exist itself. In such cases the function $ifEmpty() from the expression reference helps to automatically insert a default value instead of aborting execution.
Founder of NordFlux. Spent four years automating processes at enterprise scale at Dräger, and now brings that depth to the mid-market — pragmatic and with full data sovereignty.
Certifications
How n8n loops through items automatically, how the Loop Over Items node works, and which batch size makes sense for performance and rate limits.
Setting up and securing n8n webhooks correctly: Header Auth, JWT, IP whitelisting, and reverse proxy configuration at a glance.
n8n Task Runners execute Code nodes in isolation instead of the main process. Here is how internal and external mode work.
Anyone who does not clearly distinguish $json, $node, and items ends up building workflows that break unexpectedly with the next data change. NordFlux develops your n8n automations with robust, traceable expressions and trains your team to use them confidently. In an initial conversation we discuss your team's current level.