FlowKit

n8n Aggregate node: combine all your items into one (complete guide)

Published 26 August 2026 · 8 min read

In n8n everything travels as a list of items, and every node runs once per incoming item. That model holds up nicely until the workflow has to produce one output: a report, a single LLM call over fifty rows, a CSV file, a Slack digest. Without grouping, you send fifty messages and pay for fifty calls. The Aggregate node (n8n-nodes-base.aggregate) is the native answer: it merges N items into one, with an array inside a field. This guide covers its two modes, its real options, the exact shape of its output, and the errors it causes when used without understanding what it does to data chaining.

The problem Aggregate solves

A paginating HTTP Request, a Split Out unfolding an array, a database read: all of them produce N items. Yet some nodes only make sense when called once. Sending a digest, writing a single file, asking a model to summarise a whole corpus — those operations want the full batch, not one item at a time.

This tension is not specific to n8n. In stream processing it is known as a blocking operator: an operator that cannot emit anything until it has consumed its entire input. Brian Babcock, Shivnath Babu, Mayur Datar, Rajeev Motwani and Jennifer Widom make it one of the hard points of their reference paper "Models and Issues in Data Stream Systems", published in 2002 in the proceedings of the ACM PODS symposium (see on Google Scholar): aggregations and sorts block the pipeline, and a blocking operator sitting at the root of the query tree behaves very differently from one wedged in the middle. The Aggregate node is exactly that — a blocking operator — and most of its traps follow from that nature.

Mode 1: Individual Fields

The node's main parameter is called Aggregate and offers two values. The first, Individual Fields, aggregates field by field.

For each field to collect, you fill in:

  • Input Field Name: the name of the field to aggregate in the incoming data (email, amount, customer.name in dot notation);
  • Rename Field: a toggle that, once on, reveals Output Field Name so you can choose the output key.

The add button lets you stack several fields: each becomes an independent array inside the output item.

Three options are worth knowing:

  • Disable Dot Notation: turns off reading parent.child as a path. Enable it if your data literally contains a dot in a field name;
  • Merge Lists: when the aggregated field already holds arrays, this option outputs a single flat list rather than a list of lists. That is the difference between [["a","b"],["c"]] and ["a","b","c"];
  • Keep Missing And Null Values: by default, an item lacking the field contributes nothing to the array. Switched on, this option adds a null entry instead, which preserves index alignment across several aggregated fields.

An Include Binaries option is also available: it controls whether binary data is carried along, which it is not by default.

Mode 2: All Item Data (Into a Single List)

The second mode sorts nothing: it takes each whole item and stacks it in one array.

  • Put Output in Field: the name of the field that will receive the array. The default value is data;
  • Include: three choices — All Fields (keep everything), Specified Fields (which reveals Fields To Include, a comma-separated list) and All Fields Except (which reveals Fields To Exclude, same format).

This mode is the reflex when you want to keep the full payload. Include set to All Fields Except is particularly useful just before an LLM call: you drop the technical fields (internal IDs, sync timestamps, blobs) so they do not waste context window.

The exact output shape

This is the part that confuses people most, so let us spell it out: Aggregate always produces exactly one item. What changes is the internal structure.

In All Item Data mode with Put Output in Field left at data, three incoming items give:

{
  "data": [
    { "email": "a@example.com", "amount": 120 },
    { "email": "b@example.com", "amount": 340 },
    { "email": "c@example.com", "amount": 90 }
  ]
}

In Individual Fields mode with two declared fields, email and amount, the same data gives:

{
  "email": ["a@example.com", "b@example.com", "c@example.com"],
  "amount": [120, 340, 90]
}

Arrays follow the incoming item order — which is why placing a Sort node right before matters when the final report's order counts. And in both cases downstream access is by index: {{ $json.data[0].email }} or {{ $json.email[0] }}. To count elements, {{ $json.data.length }}.

Split Out and Aggregate: the round trip

Aggregate is one half of a pair. Split Out unfolds an array field into N items, Aggregate recomposes N items into one item holding an array. The classic pattern chains Split Out → per-item processing → Aggregate, and our guide on Split Out and Aggregate walks through that data model end to end.

One caveat: the round trip is not symmetric. Split Out can propagate the parent item's fields onto each child, but Aggregate does not rebuild them. If you had an order_id at parent level and 12 unfolded lines, aggregating gives you back 12 lines — not the original structure. Rebuilding the wrapper takes an Edit Fields (Set) node or a Code node after the aggregation.

Aggregate, Summarize or Merge?

Three nodes that get mixed up regularly:

  • Aggregate collects without transforming. Values land as-is in arrays, nothing is computed, nothing is lost;
  • Summarize computes. It applies statistical aggregations (sum, average, count, min, max, concatenate) and can group by a field, exactly like a SQL GROUP BY. Our Summarize node guide covers that ground; the rule of thumb: "revenue per sales rep" is Summarize, "the 200 raw rows in one item" is Aggregate;
  • Merge joins two distinct workflow inputs, by position, by key or by appending. It works across branches, whereas Aggregate works inside a single branch — see our article on the Merge node.

Aggregate is not a "single batch"

The query "aggregate items into single batch" hides a stubborn misunderstanding. Grouping items into one item has nothing to do with batch processing. The Loop Over Items node splits N items into batches of a chosen size and cycles through them: the goal is pacing, typically respecting an API rate limit. Aggregate paces nothing, it changes the shape of the data so a node runs only once.

The gain from aggregating before a network call is nonetheless real and long documented. Phillip Bogle and Barbara Liskov measured it in "Reducing Cross Domain Call Overhead Using Batched Futures", presented at the OOPSLA conference in 1994 (see on Google Scholar): domain crossings often cost substantially more than the work the call actually performs, and batching possibly interrelated calls into a single request cuts that cost significantly. Thirty years on, the reasoning applies verbatim to an Aggregate node placed in front of a pay-per-call API.

Four concrete use cases

  • One LLM prompt over 50 rows. All Item Data, then a prompt referencing {{ JSON.stringify($json.data) }}. One call instead of fifty, and crucially a model that sees the whole set and can compare — the foundation of long-document summarisation workflows;
  • The JSON body of a bulk HTTP call. Many APIs expose a /bulk or /batch endpoint accepting an array of objects. An Aggregate in All Item Data mode builds precisely that array, then injected into the HTTP Request node's body;
  • A single CSV or report. The Convert to File node expects the complete batch; an upstream Aggregate guarantees one file rather than one file per row, as detailed in our guide to extracting and generating Excel and CSV files;
  • A daily Slack digest. Individual Fields on the title and url fields, then an expression building a bullet list from the two arrays. One message a day, not one message per article.

The classic traps

  • Losing the $('Node').item chain. This is trap number one. The single item produced descends from N items at once: n8n can no longer establish the one-to-one match, and an expression like $('HTTP Request').item.json.id fails. Our article on the paired item error explains the mechanism; the practical fix is to carry the needed fields into the aggregation, upstream of the Aggregate node;
  • Memory blow-up. A single item holding 100,000 rows is loaded entirely in memory, and it is also stored that way in saved execution data. Aggregate after filtering and limiting, never before;
  • Silent null values. In Individual Fields mode, an item without the field produces no entry: two aggregated fields can end up with arrays of different lengths, and your indices drift apart. Keep Missing And Null Values solves exactly that;
  • Aggregating inside a loop. An Aggregate placed on the "loop" branch of a Loop Over Items only aggregates the current batch. For a global result it belongs on the "done" output, after the loop;
  • Binary data left behind. Attachments and files do not follow by default; the Include Binaries option exists, but aggregating binaries stays expensive — read our guide on handling large files before attempting it;
  • Confusing 1 item with 1 value. After Aggregate, $json.email is an array, not a string. An expression written as it was before the aggregation will yield a@x.com,b@x.com,c@x.com through implicit coercion, which sometimes goes unnoticed until a recipient receives a concatenated address.

Key takeaways

Aggregate turns N items into one, full stop. Two modes: Individual Fields to collect chosen fields into named arrays, All Item Data (Into a Single List) to stack complete items under the key set by Put Output in Field. The options that genuinely matter are Merge Lists (flatten arrays of arrays) and Keep Missing And Null Values (preserve index alignment). Finally, remember the two consequences: the output is addressed by index, and the $('Node').item chain does not survive the operation.

Going further

The "aggregate before the model call" pattern sits at the heart of the RAG Assistant Pack (€119) workflows, where passages retrieved from the vector database are grouped into a single context before reaching the LLM. On the email side, the AI Inbox Pack (€79) applies the same mechanics to produce a daily digest: one summary message rather than one notification per processed email.

FAQ

Frequently asked questions

How do I aggregate all items into a single item in n8n?

Add an Aggregate node and pick the « All Item Data (Into a Single List) » mode. It produces one item whose field, named by Put Output in Field (default: data), holds an array with the full JSON of every incoming item. Fifty items in become one item out, so every downstream node runs exactly once. The Include parameter also lets you keep only part of the payload, through Specified Fields or All Fields Except.

What does the Aggregate node actually output?

Always a single item. In All Item Data mode the output looks like {"data": [{...}, {...}, {...}]}: an array of JSON objects under the chosen key. In Individual Fields mode the output holds one key per aggregated field, each mapped to an array of values, for instance {"email": ["a@x.com", "b@x.com"], "amount": [120, 340]}. Arrays follow the incoming item order, which lets you match indices across several aggregated fields.

What is the difference between the Aggregate and Summarize nodes?

Aggregate collects: it stacks values as-is into arrays and loses nothing. Summarize computes: it applies statistical aggregations (sum, count, average, min, max, concatenate) and can group by a field, much like a SQL GROUP BY or a pivot table. If you want revenue per sales rep, that is Summarize. If you want 200 raw rows inside one item to feed an LLM or build a file, that is Aggregate.

Why do I get a paired item error after an Aggregate node?

Because aggregation breaks the trace between output item and input items. The single item produced descends from N items at once, so n8n can no longer resolve an expression such as $('Previous Node').item, which assumes a one-to-one match. The fix is to carry the fields you will need into the aggregation itself, upstream of the Aggregate node, using an Edit Fields (Set) node, rather than reaching back for them afterwards.

Bundle FlowKit Complet

€269