Affiliate/Ads disclaimer: Some links on this blog are affiliate/ads links to support this project going on, meaning I may earn a commission at no extra cost to you.
n8n Scaling: Concurrency, PostgreSQL & Worker Queue Configuration
Scaling n8n for production demands three deliberate, interconnected configurations: horizontal scaling via queue mode — splitting n8n into a main process, Redis message broker, and independent worker processes; N8N_CONCURRENCY_PRODUCTION_LIMIT — a single environment variable that caps concurrent productions across both regular and queue modes; and PostgreSQL — the required production database that replaces SQLite for crash safety, concurrent writes, and multi‑worker shared state. This guide provides tested production configurations for each layer. [1] [2]
How do you scale n8n horizontally with queue mode, Redis, and multiple workers?
Horizontal scaling in n8n is achieved through queue mode — a distributed architecture where the main n8n process handles the UI, API, and trigger listening while separate worker processes pull jobs from a Redis‑backed BullMQ queue and execute workflows independently. PostgreSQL serves as the shared persistence layer across all components. [1]
In this architecture, the main process never executes workflows directly — it only enqueues jobs. Workers run a tight polling loop and are entirely stateless, meaning you can add or remove them without downtime, and a single worker failure never costs queued jobs. The execution flow follows six distinct steps: (1) the main instance generates an execution from a trigger, (2) pushes the execution ID into Redis, (3) an available worker picks up the message, (4) the worker retrieves full workflow data from PostgreSQL, (5) executes the workflow using the shared encryption key, and (6) writes results back to PostgreSQL and signals completion to Redis. For the internal engine mechanics behind this flow, see the execution engine & queue mode guide.
| Component | Role | Scaling Method | Failure Impact |
|---|---|---|---|
| Main Process | UI, API, trigger listening, job enqueueing | Vertical (single instance) | Blocks new UI sessions; queued jobs persist in Redis |
| Redis | Message broker (BullMQ queue) | Cluster / Sentinel for HA | Prevents new job dispatch; existing workers stall |
| Workers | Execute workflow jobs independently | Horizontal (add more workers) | Single worker loss: jobs redistributed |
| PostgreSQL | Workflows, credentials, execution history | Read replicas, connection pooling | Blocks all state access; use HA with replicas |
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. When set to a value other
than the default -1 (disabled), it overrides any per‑worker
--concurrency flag in queue mode and becomes the global
ceiling for the entire deployment.
[2]
[4]
In regular mode, this variable is the only concurrency gate — set it to
a reasonable value (e.g., 20) to prevent event‑loop thrashing
from simultaneous heavy executions. In queue mode, each worker additionally
accepts a --concurrency=N startup flag (default 10), but if
the global limit is set to any value other than -1, n8n
uses that value instead and ignores the per‑worker flag entirely. For
production, start with N8N_CONCURRENCY_PRODUCTION_LIMIT=25
and monitor CPU and memory before raising it. Executions beyond the limit
are held in Redis and processed in FIFO order as slots free up
[5].
For how concurrency interacts with memory per execution, see the
execution engine memory guide.
How do you configure PostgreSQL for n8n production scaling and crash safety?
Replace SQLite with PostgreSQL by setting DB_TYPE=postgresdb
along with DB_POSTGRESDB_HOST, DB_POSTGRESDB_PORT,
DB_POSTGRESDB_DATABASE, DB_POSTGRESDB_USER, and
DB_POSTGRESDB_PASSWORD. PostgreSQL is mandatory for queue mode —
SQLite cannot handle concurrent writes from multiple workers and will
corrupt under multi‑process access.
[6]
For production deployments, use at minimum PostgreSQL 13+ with connection
pooling via PgBouncer or the built‑in DB_POSTGRESDB_POOL_SIZE
setting. Enterprise‑grade deployments use PostgreSQL HA with primary‑replica
replication — the primary handles all writes while replicas serve read
queries from the n8n UI and API, reducing load on the write master
[7].
For S3‑backed binary data storage (mandatory in queue mode — filesystem
storage is not supported), set
N8N_EXTERNAL_STORAGE_S3_BUCKET and related variables. For a
complete production deployment walkthrough including Traefik SSL
termination, see the
self‑hosting security hardening guide.
How many workers do you need and how do you configure their concurrency?
There is no single correct number of workers — it depends on workload type. A safe starting rule: one worker per available vCPU core for CPU‑bound workflows (data processing, CSV parsing), and two to three workers per core for I/O‑bound workflows (API polling, webhook forwarding) where workers spend most time waiting on external services. [8] [9]
Each worker is launched via the n8n worker CLI command
and connects to the same Redis and PostgreSQL instances as the main
process. The --concurrency flag defines how many jobs a
single worker runs in parallel (default 10). For I/O‑heavy workflows,
increase this to 15–25; for CPU‑heavy workflows, keep it at 5–10 and
scale by adding more workers instead of raising per‑worker concurrency.
The environment variable QUEUE_WORKER_TIMEOUT (deprecated;
use N8N_GRACEFUL_SHUTDOWN_TIMEOUT instead) controls how
long a worker waits for running jobs to finish before shutting down
[5].
For production deployments that require isolated Code node execution,
pair workers with external Task Runners as described in the
Code node transformation guide.
How do multi‑main setups provide high availability in n8n queue mode?
Multi‑main mode allows running multiple n8n main processes that all share the same PostgreSQL database and Redis instance. Each main process serves the UI and API independently, and webhooks can be load‑balanced across them. This provides high availability: if one main process fails, the others continue serving users and enqueueing jobs without interruption. [1]
To configure multi‑main, deploy multiple instances of n8n with
EXECUTIONS_PROCESS=main behind a load balancer. All
instances must share the same N8N_ENCRYPTION_KEY so that
workers can decrypt credentials regardless of which main process
enqueued the job. Database migrations must be run from a single main
instance — running them concurrently from multiple instances causes
race conditions. Worker groups (a 2026 feature) let you assign specific
workers to specific tasks or workflow types, preventing heavy
workloads from starving lighter ones. For the complete multi‑main
Docker Compose configuration including Traefik labels and health
checks, see the
production security hardening guide.
| HA Component | Configuration | Key Requirement |
|---|---|---|
| Multi‑Main | 2+ instances with EXECUTIONS_PROCESS=main behind load balancer |
Same N8N_ENCRYPTION_KEY across all instances |
| Redis HA | Redis Sentinel or Cluster with 3+ nodes | Automatic failover; configure QUEUE_BULL_REDIS_SENTINEL |
| PostgreSQL HA | Primary + 1–2 replicas with streaming replication | Automated failover via Patroni or cloud‑managed |
| Worker Redundancy | 2+ workers with identical config | Stateless; any worker can execute any workflow |
What does a complete production n8n scaling blueprint look like for heavy workloads?
A production‑grade stack runs on Docker Compose with at minimum five
services: n8n-main (UI and triggers), n8n-worker
(scalable execution), redis (BullMQ queue), postgres
(persistence), and an optional task-runner for isolated
Code node execution. All services connect through a shared Docker
network with environment variables precisely matching across containers.
[10]
[8]
Critical configuration flags include
EXECUTIONS_MODE=queue (tells n8n to use Redis rather than
executing locally), QUEUE_BULL_REDIS_HOST (Redis address),
DB_TYPE=postgresdb with PostgreSQL credentials,
a unique N8N_ENCRYPTION_KEY shared across main and worker,
N8N_CONCURRENCY_PRODUCTION_LIMIT for global concurrency
control, and --concurrency per worker for fine‑tuning.
Binary data must be stored in S3‑compatible external storage — filesystem
storage does not work in queue mode. For a production readiness
checklist covering SSL termination, firewall rules, Basic Auth, and
audit logging, refer to the
self‑hosting security hardening guide.
References
- n8n Documentation — Queue Mode & Horizontal Scaling
- n8n Documentation — Self‑hosted Concurrency Control
- Contabo — n8n Queue Mode Setup Guide for VPS Scalability (Feb 2026)
- DeepWiki — Queue Mode and Horizontal Scaling | n8n-io/n8n-docs
- n8n CLI Commands — Mintlify Official Reference (Feb 2026)
- n8n Documentation — Docker Installation with PostgreSQL
- Railway — Deploy n8n Enterprise-Ready Stack with PostgreSQL HA (Jan 2026)
- LumaDock — Scaling n8n with Redis and multiple workers on a VPS (Dec 2025)
- Toolient — Workers and Concurrency in n8n: Complete Scaling Guide (Dec 2025)
- n8nNode — Mastering n8n in Production with Queue Mode (Apr 2026)

