n8n’s execution system supports two fundamental operational modes that
determine how workflows are processed. Regular mode
(default) runs everything — API, UI, webhooks, trigger polling, and
workflow execution — in a single Node.js process with no Redis dependency,
using either SQLite or PostgreSQL, suitable for small deployments and
development. Queue mode enables horizontal scaling by
distributing workflow executions across multiple worker processes
coordinated via Redis, separating the main process (UI/API/webhook
reception) from workers (execution), and requiring PostgreSQL
because SQLite cannot handle concurrent multi-process writes. A single
environment variable — N8N_CONCURRENCY_PRODUCTION_LIMIT —
controls production execution concurrency in both modes, overriding
per-worker --concurrency flags.
[1]
[2]
| Dimension | Regular Mode | Queue Mode |
|---|---|---|
| Execution model | Single-process: API, UI, webhooks, execution in one Node.js process [3] | Distributed: main process handles UI/API/triggers; workers handle execution via Redis [2] |
| Best for | Small deployments, development, testing [2] | Production, high-volume, horizontal scaling [2] |
| Scaling approach | Vertical (increase process resources) [2] | Horizontal (add worker processes) [2] |
| Redis required | ❌ No [3] | ✅ Yes (Redis ≥6.0 + Bull) [3] |
| Database | SQLite or PostgreSQL [2] | PostgreSQL (required) [1] |
| Enabled via | Default [3] | EXECUTIONS_MODE=queue [1] |
How does n8n’s stack-based execution engine process nodes sequentially?
n8n uses a stack-based execution model through the
WorkflowExecute class. It initialises a node execution
stack containing the trigger node, then processes nodes
sequentially via processRunExecutionData(). After each
node executes, the engine captures its output JSON and routes data to
downstream nodes by calling addNodeToBeExecuted(),
maintaining full execution state until every node is complete.
[4]
[5]
The engine supports two execution orders: v0 (legacy) and
v1, configured via the N8N_EXECUTION_ORDER environment
variable. The WorkflowRunner class is the primary entry point — it
decides between regular in-process execution via
runMainProcess() and distributed queue-based execution
via enqueueExecution(). The ActiveExecutions service
tracks all currently running executions in the process, manages response
promises for webhook-triggered workflows, and provides cancellation
capabilities. For a complete breakdown of node execution order across
parallel branches — where the leftmost branch with the highest y-position
executes first, and you can reorder branches in workflow settings via
Parallel Branch Execution Order — see the
IF & Switch node branching guide.
How does queue mode distribute workflow executions using Redis and workers?
Queue mode splits n8n into three logical process types: the main process handles the editor UI, REST API, and trigger listening (webhooks, schedules, polling); Redis (≥6.0 required) acts as the message broker via the Bull job queue library, holding job descriptions with workflow IDs, trigger data, and credential references; and worker processes continuously poll Redis, grab available jobs, and execute them via WorkflowExecute independently. [2] [3]
The execution follows a precise six-step flow: (1) the main
process receives a trigger event and generates a workflow execution; (2)
it stores the initial execution record in PostgreSQL; (3) the execution ID
is pushed to the Redis Bull queue with workflow metadata; (4) the next
available worker picks up the job from the Redis queue; (5) the worker
fetches the complete workflow definition and credentials from PostgreSQL
using the execution ID; (6) the worker executes the workflow nodes,
writes results back to PostgreSQL, and signals completion to Redis
[2].
Critically, the main process never executes workflows directly in queue
mode — it only enqueues jobs. A fourth optional process type, the
webhook processor, can be deployed independently to
scale incoming webhook handling. 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 so workers
can decrypt credentials stored in PostgreSQL
[1].
For the complete production deployment blueprint, see the
n8n Docker Compose production stack guide.
Why does queue mode require PostgreSQL, and what happens if you use SQLite?
n8n recommends PostgreSQL 13+ for queue mode. Running queue mode with an SQLite database is not recommended and will cause corruption. The reason is architectural: in queue mode, multiple worker processes must read and write workflow definitions, execution state, and results concurrently. SQLite serializes all writes through a single file-level lock — under concurrent multi-process access, writes queue sequentially, last-write-wins race conditions corrupt execution state, and worker processes encounter “database is locked” errors. [1] [2]
PostgreSQL handles this natively through MVCC (Multi-Version Concurrency
Control) with row-level locking — multiple workers can read and write
simultaneously without blocking each other. For production deployments,
configure DB_TYPE=postgresdb with the required
DB_POSTGRESDB_HOST, DB_POSTGRESDB_PORT (default
5432), DB_POSTGRESDB_DATABASE, DB_POSTGRESDB_USER,
and DB_POSTGRESDB_PASSWORD variables. For SSL-encrypted
connections, set DB_POSTGRESDB_SSL_ENABLED=true. For high-
availability PostgreSQL, deploy with primary-replica replication and
connection pooling via PgBouncer or the built-in
DB_POSTGRESDB_POOL_SIZE setting. The main process writes
initial execution records and the workers write results back — both
must reach the same database. For the complete database selection guide
covering SQLite vs PostgreSQL performance benchmarks and migration
procedures, see the
n8n Database: SQLite vs PostgreSQL guide.
How does N8N_CONCURRENCY_PRODUCTION_LIMIT control execution concurrency in both modes?
N8N_CONCURRENCY_PRODUCTION_LIMIT is a single environment
variable that caps the number of production executions running
simultaneously in both regular and queue modes. Its
default is -1 (disabled in regular mode). 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. Concurrency control applies
only to production executions — those started from
webhooks or trigger nodes — not to manual executions or sub-workflow calls.
[6]
[7]
In regular mode, this variable is the only concurrency gate — without it,
n8n imposes no limit on simultaneous production executions, which can
thrash the event loop and cause performance degradation. Set it to a
reasonable value (e.g., export N8N_CONCURRENCY_PRODUCTION_LIMIT=20)
to protect the instance. In queue mode, each worker additionally accepts a
--concurrency=N startup flag (default: 10). But if
N8N_CONCURRENCY_PRODUCTION_LIMIT is set to any value other
than -1, n8n takes the limit from this variable and ignores the
per-worker flag entirely. Concurrency less than 5 can lead to
an unstable environment — consider setting it to at least 5 for best
performance. Executions beyond the limit are held in queue 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. For
comprehensive scaling strategies including worker count tuning and
horizontal scaling patterns, see the
n8n Scaling & Queue Configuration guide.
How do execution timeouts and the execution lifecycle control long-running workflows?
n8n provides two-tier timeout control.
EXECUTIONS_TIMEOUT sets a default timeout (in seconds) for
all workflows — defaults to -1 (disabled). When a
workflow exceeds this duration, n8n attempts a soft timeout
first (waits for the current node to finish), then kills the process
after waiting for a fifth of the given timeout duration.
EXECUTIONS_TIMEOUT_MAX sets the maximum timeout users can
configure per individual workflow — defaults to 3600 seconds
(1 hour). Example: export EXECUTIONS_TIMEOUT=3600 for a
1-hour default, export EXECUTIONS_TIMEOUT_MAX=7200 for a
2-hour ceiling.
[8]
[9]
The execution lifecycle is managed by WorkflowRunner and tracked by
ActiveExecutions. Production executions — those fired by webhooks or
triggers — are the only ones subject to concurrency control. Manual
executions (from the editor UI), sub-workflow calls, error executions,
and CLI executions (n8n execute --id=N) are exempt. Queued
executions cannot be retried — cancelling or deleting a queued execution
removes it from the queue. For execution data management, the system
provides pruning controls: EXECUTIONS_DATA_MAX_AGE defaults
to 336 hours (14 days), and
EXECUTIONS_DATA_PRUNE_MAX_COUNT defaults to
10,000 executions retained in the database. For
monitoring concurrency, watch logs for executions being added to and
released from the queue. For complete error handling and retry
patterns that catch timeout failures, see the
n8n Error Handling nodes guide.
N8N_CONCURRENCY_PRODUCTION_LIMIT=20 to prevent
event-loop thrash. (2) In queue mode, this overrides per-worker
--concurrency. (3) Default per-worker concurrency
is 10; minimum recommended is 5. (4) Excess executions are queued
in FIFO order. (5) Concurrency applies only to production
executions — manual and sub-workflow executions are exempt.
[6]
References
- n8n Documentation — Queue Mode: horizontal scaling architecture, encryption key sharing, PostgreSQL requirement, S3 for binary data, Redis setup
- DeepWiki — Workflow Execution System: regular vs queue mode comparison (process models, scaling, database), six-step queue mode flow, execution lifecycle (Apr 2026)
- DeepWiki — Runtime Architecture and Process Models: N8N_EXECUTIONS_MODE env var, main/worker/webhook process types, Bull queue library, Redis dependency (Apr 2026)
- DeepWiki — Workflow Execution Engine: WorkflowRunner entry point, WorkflowExecute stack-based model, ActiveExecutions tracking, v0/v1 execution orders (Feb 2026)
- DeepWiki — Workflow Execution Lifecycle: execution entry points (manual, webhook, sub-workflow), mode selection logic, registration and engine invocation phases (Apr 2026)
- n8n Documentation — Self-hosted Concurrency Control: N8N_CONCURRENCY_PRODUCTION_LIMIT (-1 default), production-only scope, FIFO queue, comparison to queue mode
- n8n CLI Commands — Mintlify: worker command, –concurrency flag, N8N_CONCURRENCY_PRODUCTION_LIMIT override, QUEUE_WORKER_TIMEOUT (Feb 2026)
- n8n Documentation — Configure Workflow Timeout Settings: EXECUTIONS_TIMEOUT (-1 default), soft timeout then force kill, EXECUTIONS_TIMEOUT_MAX (3600 default)
- n8n Docs (TeamLab) — Executions Environment Variables: EXECUTIONS_TIMEOUT, EXECUTIONS_TIMEOUT_MAX (3600), concurrency limit, pruning settings (336h, 10000 count)
- Contabo — n8n Queue Mode Setup Guide for VPS Scalability: Redis ≥6.0 requirement, Docker Compose service order, PostgreSQL 13+ recommendation (Feb 2026)

