n8n’s execution engine is built on a stack‑based, sequential processing
model implemented by the WorkflowExecute class — it maintains a node
execution stack, processes nodes one by one via
processRunExecutionData(), and routes data downstream through
addNodeToBeExecuted(). The WorkflowRunner serves
as the primary entry point, deciding at execution time between regular
mode (direct in‑process execution via
runMainProcess()) and queue mode (distributed
execution via enqueueExecution() through a Redis‑backed Bull job
queue). Queue mode requires PostgreSQL because SQLite cannot handle concurrent
multi‑process writes, uses Redis ≥6.0 as the message broker, and distributes
jobs to worker processes that independently fetch workflow
definitions from PostgreSQL, execute nodes, and write results back [1]
[2].
| Dimension | Regular Mode | Queue Mode |
|---|---|---|
| Execution Model | Single-process: API, UI, webhooks, and execution all in one Node.js process [5] | Distributed: main process handles UI/API/triggers; workers handle execution via Redis [2] |
| Best For | Small deployments, development, testing [6] | Production, high-volume, horizontal scaling [6] |
| Redis Required | ❌ No [5] | ✅ Yes (Redis ≥6.0 + Bull) [5] |
| Database | SQLite or PostgreSQL [6] | PostgreSQL (required) [6] |
| Enabled Via | Default [5] | EXECUTIONS_MODE=queue [6] |
How does n8n’s stack-based engine determine node execution order in parallel branches?
n8n processes nodes sequentially using a stack-based model
maintained by the WorkflowExecute class: it initialises a node
execution stack with the trigger, processes each node via
processRunExecutionData(), captures its output JSON, and
routes data to downstream nodes with addNodeToBeExecuted(),
repeating until the stack empties. The engine supports two execution
orders: v0 (legacy) and v1 (recommended).
[1]
[3]
In v1 mode, n8n completes each branch in turn before
moving to the next — branches are ordered by their position on the
canvas from topmost to bottommost; if two branches sit at the same
height, the leftmost executes first. In v0 mode, n8n
executes the first node of every branch, then the second node of every
branch, and so on — interleaving execution across branches. The execution
order is configurable per workflow under Workflow Settings → Parallel
Branch Execution Order. V1 is recommended for all workflows created in
version 1.0 and above; v0 remains available as a legacy option for
compatibility. The ActiveExecutions service tracks all
currently running executions, managing response promises for webhook-
triggered workflows and providing cancellation via
finalizeExecution() [1].
For a complete walkthrough of the WorkflowExecute class and the
runMainProcess() vs enqueueExecution()
decision, see the n8n Node Execution Hub.
How does queue mode distribute workflow executions using Redis, workers, and PostgreSQL?
Queue mode splits n8n into three logical component types: the main process serving the editor UI, REST API, and trigger listening; Redis ≥6.0 acting as the message broker via the Bull job queue library; and worker processes continuously polling Redis for jobs, executing workflows independently via WorkflowExecute, and writing results back to PostgreSQL [2] [5].
Queue mode requires PostgreSQL because SQLite cannot
handle concurrent multi-process writes: multiple worker processes must
read and write workflow definitions, execution state, and results
simultaneously — SQLite’s file-level write lock causes “database is
locked” errors and corruption under this load [6].
PostgreSQL handles this natively through MVCC with row-level locking.
The complete six‑step flow: (1) trigger reception generates
an execution, (2) execution record stored in PostgreSQL, (3) execution ID
pushed to Redis Bull queue, (4) next available worker pops the job, (5)
worker fetches full workflow definition and credentials from PostgreSQL,
(6) worker executes all nodes and writes results back to PostgreSQL [2].
Workers are stateless: you can add or remove them without downtime, and a
single worker failure never loses queued jobs. The encryption
key (N8N_ENCRYPTION_KEY) must be identical across
the main process and every worker. For the complete production deployment
blueprint with Docker Compose, see the n8n Docker Compose production stack guide.
How does N8N_CONCURRENCY_PRODUCTION_LIMIT control how many workflows run simultaneously?
N8N_CONCURRENCY_PRODUCTION_LIMIT is a single environment
variable that caps the number of production executions running at the
same time — in both regular and queue modes. It
defaults to -1 (disabled). When set to any value other
than -1, it overrides the per-worker --concurrency flag in
queue mode and becomes the global ceiling for the entire deployment. This
limit applies only to production executions from webhooks and trigger
nodes — manual executions, sub-workflow calls, error executions, and CLI
executions are exempt [7].
Set it to a reasonable value (e.g., export N8N_CONCURRENCY_PRODUCTION_LIMIT=20)
to prevent event-loop thrashing caused by too many simultaneous production
executions [7].
In queue mode, if this variable is -1, each worker’s concurrency is
determined by its --concurrency startup flag (default:
10 per worker) [8].
The per-worker default of 10 means each worker runs up to 10 jobs in
parallel; a value less than 5 can lead to an unstable environment [8].
Executions beyond the limit are queued and processed in FIFO
order as slots free up. On instance startup, n8n resumes queued
executions up to the concurrency limit and re-enqueues the rest. The
environment variable’s value is consumed once at startup; runtime changes
require a restart [7].
For complete scaling strategies including worker-to-core ratios and
high-availability configurations, see the n8n Scaling & Queue Configuration guide.
N8N_CONCURRENCY_PRODUCTION_LIMIT=20 to prevent event-loop
thrash in regular mode. (2) In queue mode, this variable overrides
per-worker --concurrency (default 10 per worker). (3)
Concurrency less than 5 can cause instability. (4) Excess executions
are queued in FIFO order. (5) This limit applies only to production
executions — manual, sub-workflow, error, and CLI executions are exempt.
[7]
How does n8n manage memory, how much does each execution consume, and what causes OOM errors?
n8n does not restrict the amount of data each node can fetch and process — it uses a Node.js 18 runtime where the V8 engine manages heap memory. Memory consumption scales with three primary factors: the volume of JSON data passing through nodes, the size of binary data, and the number of nodes in a workflow. Code nodes and the legacy Function node increase consumption significantly [9].
On n8n Cloud, the memory limit varies by plan: 320–640 MiB
for Starter/Pro [10].
On self-hosted instances, you can increase the V8 heap size via
NODE_OPTIONS="--max-old-space-size=SIZE" or scale the
container memory [9].
Telltale warning signs include “Execution stopped at this node (n8n may
have run out of memory)” messages, “Allocation failed — JavaScript heap
out of memory” in server logs, and Connection Lost or 503 Service
Temporarily Unavailable responses [9].
To reduce memory consumption: process data in smaller chunks (e.g., 200
rows instead of 10,000), avoid manual executions (n8n duplicates data
for the frontend), and split large workflows into sub-workflows so each
returns only limited output to the parent [9].
For the complete memory tuning and monitoring guide, see the n8n Node Execution Hub.
How do execution timeouts work, and how do they control long-running workflows?
n8n provides two-tier timeout control. The first tier,
EXECUTIONS_TIMEOUT, sets a default timeout in seconds for all
workflows — it defaults to -1 (disabled). When set, n8n
first attempts a soft timeout (waits for the current node
to finish), then kills the process after waiting for a fifth of the given
timeout duration [11].
The second tier, EXECUTIONS_TIMEOUT_MAX, sets the maximum
timeout users can configure per individual workflow — defaulting to
3600 seconds (1 hour) [12].
Example: export EXECUTIONS_TIMEOUT=3600 for a 1-hour default
across all workflows, and export EXECUTIONS_TIMEOUT_MAX=7200
for a 2-hour ceiling on per-workflow overrides. This two-tier system
means the instance admin can enforce a hard global ceiling that no
individual workflow can exceed. Users can override
EXECUTIONS_TIMEOUT in the Settings tab of each individual
workflow up to the EXECUTIONS_TIMEOUT_MAX ceiling. For AI
and LLM nodes (OpenAI, Anthropic, Mistral, Ollama) that may need longer
processing, a separate N8N_AI_TIMEOUT_MAX variable controls
the HTTP request timeout at 3,600,000 ms (1 hour)
default [12].
For complete error handling and retry patterns that catch timeout
failures, see the n8n Error Handling nodes guide.
EXECUTIONS_TIMEOUT = default per-workflow ceiling
(default: -1, disabled). EXECUTIONS_TIMEOUT_MAX =
max per-workflow override (default: 3600 seconds / 1 hour).
N8N_AI_TIMEOUT_MAX = AI node HTTP timeout (default:
3,600,000 ms / 1 hour). Soft timeout fires first (current node
finishes), then hard kill after one-fifth the timeout duration.
[11]
How does the complete regular-mode execution lifecycle go from trigger to data written to database?
In regular mode, the lifecycle begins when a trigger
fires (webhook, schedule, manual). The WorkflowRunner
is the primary entry point that decides between runMainProcess()
and enqueueExecution() based on the
executions.mode configuration [13].
Regular mode takes the runMainProcess() path — executing the
entire workflow in the current Node.js process.
The lifecycle progresses through four phases. Phase 1 — Registration:
ActiveExecutions.add() creates the execution record and
ExecutionRepository.setRunning() marks the start time in the
database. Phase 2 — Engine Invocation:
WorkflowExecute.run() initialises the node execution stack.
Phase 3 — Node Processing: the engine pops each node from
the stack, executes it, captures its output JSON, routes data to downstream
nodes via addNodeToBeExecuted(), and repeats until the stack
empties. Phase 4 — Finalisation: results are written to the
database, binary data to configured storage, and
ActiveExecutions.finalizeExecution() releases the execution
tracking slot [13].
For production deployments above ~200 workflow executions per day, switch to
queue mode to separate the UI from execution and enable horizontal scaling —
the complete production blueprint is available in the Docker Compose production stack guide.
References
- DeepWiki — Workflow Execution Engine: WorkflowRunner entry point, WorkflowExecute stack-based model, ActiveExecutions tracking, v0/v1 execution orders, scaling service (Feb 2026)
- DeepWiki — Workflow Execution System: regular vs queue comparison, six-step queue mode flow, configuration requirements, webhook processors (Apr 2026)
- n8n Docs (TeamLab) — Workflow Settings: v0 (legacy) vs v1 (recommended) execution order, branch ordering from topmost to bottommost, leftmost first at same height
- C# Corner — How n8n Works Internally: Node.js-based engine, JSON workflow definitions, modular architecture, persistent execution tracking, scalable processing (Jan 2026)
- DeepWiki — Runtime Architecture: process models, N8N_EXECUTIONS_MODE env var, main/worker/webhook process types, Bull queue library, Redis dependency (Apr 2026)
- n8n Documentation — Queue Mode: horizontal scaling, Redis setup, PostgreSQL requirement, encryption key sharing, S3 binary data storage
- n8n Documentation — Concurrency Control: N8N_CONCURRENCY_PRODUCTION_LIMIT (-1 default), production-only scope, FIFO queue, comparison to queue mode
- Mintlify — n8n CLI Commands: worker –concurrency flag (default 10, minimum 5 for stability), N8N_CONCURRENCY_PRODUCTION_LIMIT override, graceful shutdown timeout (Feb 2026)
- n8n Documentation — Memory-related Errors: out‑of‑memory root causes (JSON volume, binary data, node count, Code nodes, manual executions), reduction strategies, V8 heap tuning
- n8n Community — Memory Limit Per Execution: Cloud Starter vs Pro plan (320–640 MiB), self-hosted NODE_OPTIONS tuning, queue mode worker memory governance
- n8n Documentation — Configure Workflow Timeout Settings: EXECUTIONS_TIMEOUT (-1 default), soft timeout then force kill, EXECUTIONS_TIMEOUT_MAX (3600 default, 7200 example)
- n8n Docs — Executions Environment Variables: EXECUTIONS_MODE, EXECUTIONS_TIMEOUT, EXECUTIONS_TIMEOUT_MAX (3600), N8N_AI_TIMEOUT_MAX (3600000 ms), pruning settings (336h, 10000 count)
- DeepWiki — Workflow Execution Lifecycle: execution registration, engine invocation, node processing loop, finalisation phases, mode selection logic (Apr 2026)

