← n8n Production Guides

GUIDE · Infrastructure

n8n Out of Memory: Why It Happens and the Fix for Each Cause

2026-10-25 · William Ayad · 10 min read

“Execution stopped at this node — n8n may have run out of memory while running this execution.” The message names a symptom, not a diagnosis, and the word may is the honest part: n8n knows the process died under memory pressure; it does not know which of six very different diseases killed it. The one-sentence root for all of them: n8n processes each execution's items in RAM, with no built-in ceiling on how much data a single step loads. Your entire debugging task is finding which pattern let one execution — or one burst of executions — exceed the machine's envelope. This guide is that hunt, ordered: the model, the six causes, the sizing math, the fixes that end crashes rather than postpone them.

Why n8n eats RAM: the execution model in one paragraph

When a workflow runs, every item passing through it exists as a JavaScript object in the executing process's heap — and by default, each node's output history stays reachable for the execution's lifetime so later nodes and expressions can reference it. Ten thousand sheet rows are not a file on disk; they are ten thousand objects plus their per-node copies. Binary files ride along the same structure unless you switched storage modes. Meanwhile the baseline keeps growing underneath: the main process, the editor, and an executions database that inflates with retention add pressure before any workflow even starts. On n8n Cloud the ceiling is your plan tier; self-hosted, it is the container limit — and when the kernel's OOM killer fires, the outside world often only sees a 503 or a “Connection lost” banner, which is why memory deaths so often masquerade as network errors.

The six causes that actually fill the RAM

1. One execution carrying a dataset that should have been a stream

The spreadsheet import, the 9,000-row Postgres query, the API endpoint that returns a whole year at once — fetched in a single step and carried through twelve nodes “for convenience”. Every downstream node adds its own copy of that payload to the retained history. The community methodology for these cases is always the same: line up crash timestamps against running workflows, and the culprit is a data-mover, not a bug.

2. Loops that accumulate instead of streaming

Split-in-batches logic that collects every chunk into an array “to merge at the end”, or Code nodes that build one growing list across a thousand iterations, re-create the all-in-RAM problem inside an innocent loop. The loop looks modest; the accumulator is not.

3. Code nodes with algorithmic appetite

Nested maps over large arrays, string building by concatenation inside big loops, JSON re-parsing of huge payloads per item — and, deadliest, a small logic error like an unterminated while loop, which consumes all allocated RAM in seconds and never touches n8n's own safeguards. A code path that worked on 200 test rows is a different organism on 200,000 production rows.

4. Sub-workflow fan-out under concurrency

An Execute Workflow node inside a loop, or several webhook entries feeding the same child workflow, multiplies live executions geometrically: parent waits while children each hold their own full item sets. Ten parents × ten children × 40MB each is not a workflow — it is a memory allocation lottery.

5. Binary files carried through the chain

PDFs, images and archives moved between HTTP Request, Code and Write nodes live in heap by default. A five-file e-mail ingest with 20MB attachments is a 100MB execution before any JSON exists at all.

6. The burst: ten webhooks in the same second

Nothing about your workflow is heavy — until a Slack event storm, a form launch, or a retried upstream batch delivers twenty triggers simultaneously, spinning up twenty parallel executions whose combined footprint never appeared in any single-run test. This cause survives every per-workflow optimization because it is a timing fault, not a size fault.

The sizing math: honest rules of thumb

Nobody can price your RAM from an article — but production reports converge on usable envelopes. Treat these as starting points to validate against your own heaviest execution, not as specifications:

Workload profileTypical contentWorking envelope
LightJSON webhooks, small records, notifications1–2 GB comfortably
MediumSheets/DB syncs in the low thousands of rows2–4 GB with chunking discipline
HeavyFiles, images, large Code-node transforms4–8 GB, or redesign the pattern

The formula that matters: peak concurrency × worst-case single-execution footprint + main process + database. Doubling instance RAM while ten simultaneous heavy executions were the real killer just buys a taller ceiling over the same room — the burst math does not change until the concurrency or the footprint does.

The fixes that end crashes (not postpone them)

Filter early, carry little. Delete unused fields the moment data enters (an Edit Fields node right after the source), paginate APIs instead of fetching a year at once, and select only needed columns in database reads. The cheapest megabyte is the one that never becomes an item.

Stream, don't accumulate. Process items in genuine batches — Loop Over Items with a few hundred records per pass, emitting results per batch instead of assembling one final array. If your loop ends with a giant merge, the loop was decoration.

Move files out of the heap. Switch binary handling to filesystem mode and reference paths instead of embedding bytes through the chain; image/PDF flows change character entirely when the binary stops visiting every node.

Tame bursts with queues. In front of trigger endpoints, rate-limit or buffer upstream (queue, throttle, or staggered schedules) so twenty events become four waves of five. Self-hosted, queue mode contains crashes to workers and parallelizes the load — isolation and scale, not more memory.

Shrink the baseline. Prune execution history aggressively (retention settings), and move to Postgres before SQLite's swelling adds I/O pressure that looks like memory pressure. The instance you protect is partly the one you refuse to let bloat.

Diagnosing after the crash: the timestamp lineup

The reliable post-mortem is boring and fast. In Executions, list the crash timestamps, then line them up against which workflows were running at those exact moments — memory spikes trace back to one or two workflows, essentially always. Self-hosted, the kernel tells the truth too: dmesg and Docker logs show OOM-kill events with the murdered process named, distinguishing “n8n used too much” from “the box was full of something else”. Crashes that began immediately after an update deserve the same lineup before the update gets blamed — nodes change default behavior, and a previously comfortable workflow crosses the line. On Cloud, where you cannot see the kernel, the same execution-timestamp lineup plus the plan ceiling answers the same question.

What dies with the worker (and why monitoring is part of the fix)

An OOM-killed process does not close gracefully: in-flight executions vanish mid-write, partial data lands in external systems, and — on the main process — webhooks go unanswered while everything looks green in the editor. That asymmetry is why the alert-on-silence layer from the monitoring guide is not optional decoration here: your first OOM symptom reaching users will be nothing happened, and silence-detection catches it before they call. For the full pre-production discipline, the heavy patterns above are checklist-shaped — run them against every new workflow with the production preflight rules.

The upgrade-first trap

When the first instinct is a bigger plan or more RAM, the failure usually returns — smaller, later, and harder to interpret. Upgrading answers the question "how much can this instance hold?", but the crashing workflow was asking "how much can one execution hold?". A heap-hungry pattern simply grows into the new envelope: the 10,000-row import becomes next quarter's 25,000-row import, and the crash lands in week five of the new tier instead of week one of the old. The correct order is always pattern first, capacity second: fix the data shape, measure the heaviest execution afterward, and only then decide whether the instance itself is undersized. Teams that upgrade first pay twice — once for capacity that did not help, and again for the diagnosis they postponed.

When the crash text is in your hands right now

If the failure text in front of you is JavaScript heap out of memory, a 503-with-green-canvas, or “Connection lost” after thirty heavy seconds, classification should take seconds, not an evening. Paste the exact crash text into the free n8n Error Doctor — it pattern-matches documented crash classes, memory-cascade signatures included, and tells you which of the six causes your text belongs to, in-browser, in about two seconds. The six-section hunt above then starts already knowing its suspect.

Frequently asked questions

Does switching to queue mode fix out of memory errors?

No — it relocates them. Queue mode isolates executions onto worker processes so a crash spares the editor, but each worker keeps its own RAM ceiling, and a 4GB execution dies in a 2GB worker exactly as before. Fix the data pattern first; use queue mode for isolation and parallelism.

How much RAM does n8n actually need?

Your largest single execution × peak concurrency + main process + database. Light JSON automations live in 1–2GB; file- and code-heavy flows routinely need 4–8GB — or a redesign. Measure your own heaviest execution; no fixed number survives contact with someone else's data.

Why did OOM errors start right after an update?

Updates shift node behavior and defaults just enough to push a borderline workflow over the edge. Line up crash timestamps against running workflows before blaming the version — the trace almost always ends at one or two specific workflows.

Does n8n Cloud have memory limits?

Yes — per-execution ceilings tied to your plan, producing the same failure message as a self-hosted container limit. Diagnosis is identical; the remedy is less data per execution or a higher tier.

The one-paragraph answer to bookmark

n8n puts every execution's data in RAM with no ceiling, so OOM is never “n8n is broken” — it is one of six patterns: giant payloads, accumulating loops, hungry Code nodes, sub-workflow fan-out, files in the heap, or bursts of concurrency. Identify yours by lining up crash timestamps against Executions, then apply the fix that matches the pattern: filter early, stream in batches, move files to filesystem mode, queue the bursts, and trim retention. More RAM without a pattern fix is a taller ceiling over the same room.

Where the free tool stops (honesty first)

The Error Doctor classifies crash text from documented failure patterns — it cannot measure your instance's RAM, weigh your datasets, or watch your bursts. That runtime layer lives in the n8n Reliability Kit: the 24-rule preflight that flags heavy-payload and zero-retry fan-out patterns before production, plus the incidence-ranked failure library behind this piece — one-time $19 launch (disclosing: mine), browser-local like the free tools.

Holding a crash text and want its cause class first?