Using item accumulation as a natural loop counter in n8n?

Describe the problem/error/question

Hi everyone,

I have a polling loop in my workflow where I check the status of a long-running job. I noticed that every time the loop goes back to the Wait node and runs the HTTP Request (Status) again, n8n accumulates these runs as new items in the branch (e.g., 1 item, then 2 items, then 3 items total in the same execution branch).

I want to turn this “accumulation” into a feature instead of a bug.

My Goal: I want to use the total number of items currently in the active branch to act as my “Max Attempts” counter. For example, if the branch reaches 20 items, I want the loop to stop.

My Questions:

  1. Is it a good practice to use {{ $input.all().length }} inside an If or Switch node to limit the number of loops based on accumulated items?

  2. Does this accumulation impact performance if the loop runs for a long time (e.g., 50+ iterations)?

  3. When the Split Out node moves to the next main item in the list, does n8n automatically “reset” this item count for the new branch, or will it keep adding to the previous total?

I’m trying to avoid using a separate Edit Fields (Set) node to manually increment a counter variable, as it feels redundant when n8n is already “counting” the runs by adding items.

Any advice on this “item-length-as-a-counter” approach would be great!

Please share your workflow

Share the output returned by the last node

Information on your n8n setup

  • n8n version: 2.13.4
  • Database (default: SQLite): SQLite
  • n8n EXECUTIONS_PROCESS setting (default: own, main): main
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker
  • Operating system: Ubuntu 24.04

Hi @atakanozban :waving_hand:
While using {{ $input.all().length }} works in a pinch, it is generally considered a “silent killer” for n8n instances in long-running loops. Here is why:

The Memory Problem When n8n accumulates items in a branch, it stores the entire JSON payload of every single execution in the server’s RAM. If your Check status node returns a large chunk of data and you loop 50 times, n8n is holding 50 full copies of that data simultaneously. This is a fast track to an Out of Memory (OOM) crash.

The Solution: Use a Manual Counter Using a small piece of JavaScript in a Code Node is much safer. It only stores a single integer, which uses virtually no memory.

1. Add a Code Node

Place a Code Node (set to “Run once for each item”) right after your Check status node and before your If node. Use this script:

let counter = 0;

// Initialize at 1 if it doesn't exist, otherwise increment
if (item.json.counter === undefined) {
  counter = 1;
} else {
  counter = item.json.counter + 1;
}

// Pass the data forward with the new counter
return {
  ...item.json,
  counter: counter
};

2. Update your If/Switch Node

instead of checking the branch length, simply check the counter field:

  • Property: {{ $json.counter }}

  • Operator: Is larger than or equal to

  • Value: 20

Thanks for the suggestion, but I’ve implemented the Code Node as you described and it’s still not working. The loop becomes infinite because the counter value doesn’t seem to persist or increment correctly across iterations.

Here is what happens: In each loop, the counter starts from the initial value (or undefined) again, instead of taking the incremented value from the previous run. Am I doing something wrong?

Thanks for sharing the screenshots. I see exactly what is happening, and it is a very common in n8n loops…

You aren’t doing anything wrong with the JavaScript itself. The issue is your Check status node.

When an HTTP Request node runs, its default behavior is to output only the new data it just fetched, overwriting the previous item data. So, when your workflow loops back around, the Check status node completely drops the counter variable you created in the previous run. By the time the data reaches your Code node again, item.json.counter is gone, so it evaluates as undefined and starts over at 1.

you have to tell the Check status node to stop throwing away the input data.

  1. Open your Check status node.

  2. Look for the settings at the bottom (usually under Options).

  3. Add the option for Include Input Fields (or Send Input Data, depending on your exact n8n version) and toggle it ON.

  4. This tells the HTTP node to merge the newly fetched status with the counter variable coming from the previous loop, allowing your JavaScript to finally see the incremented number.

Here are 2 other ways to fix the problem:

- 1: Use n8n’s built-in $runIndex - No Code

You actually don’t need the Code node at all. n8n natively tracks how many times a node has executed during a workflow using the $runIndex variable.

  1. Delete the Code node.

  2. In your If node, change the Condition to use an Expression: {{ $runIndex }}

  3. Set the operator to
    Is larger than or equal to
    and your value (e.g., 20).

Because the If node is inside the loop:

$runIndex will automatically output:

(0 ) on the first run,

(1) on the second,

(2) on the third,

and so on.

It is the perfect builtin counter that cannot be overwritten.

-2: Use the API’s data

Take a look at the incoming JSON in your first screenshot. The data returning from your Check status node already contains this field:

"attempts": 2

Does the third-party system you are polling already track the attempt count for you, If so, you can skip the Code node entirely and just set your If node to check {{ $json.attempts }}

I recommend Option 1 or Option 2, they keep your workflow much cleaner.

Let me know how it goes, please!

Thank you so much! Solution #1 (using n8n’s natural item accumulation) worked perfectly. :raising_hands:t2:

I had previously tried Solution #2 (the manual counter approach), but I couldn’t get the value to persist correctly across iterations. Using the branch’s item length as a counter is much more stable and solved my problem immediately. Thanks for the great insight!

I am so happy :smiling_face: to hear that you got your workflow up and running!

It is always a huge relief to get a tricky loop working smoothly.

Let me know if you run into any other roadblocks in the future.

Happy automating!