# n8n queue mode: Redis, workers, concurrency and scaling

> n8n queue mode splits the work between a main instance, Redis and worker processes. The main instance receives triggers and webhooks and queues each execution in Redis, and a worker picks it up and runs it. It needs PostgreSQL, Redis, one shared encryption key and a binary data mode other than filesystem. A worker runs 10 jobs at a time by default.

Mindket editors · Published 2026-11-04 · Updated 2026-11-05 · https://mindket.com/learn/n8n-advanced/n8n-queue-mode

## In short

- Know when queue mode is worth its extra moving parts.
- Run main, Redis, Postgres and workers on one shared encryption key.
- Tune worker concurrency and the Redis settings that matter.
- Pick a binary data mode that works with several workers.
- Route webhooks to processors and know what multi-main needs.

## Before you start

Queue mode is a self-hosted setup. The basics of running n8n in Docker are in the [self-hosting lesson](https://mindket.com/learn/n8n/self-host-n8n-docker), and this lesson starts where that one stops. The [queue mode page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) describes four pieces. A main instance takes the triggers and webhook calls. Worker instances run the executions. Redis is the message broker, and the database persists the data.

PostgreSQL is the database to use. The docs call queue mode on SQLite not recommended and a distributed setup over SQLite unsupported. The [database page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/choose-n8ns-database) lists PostgreSQL 17 and 18 as supported as of July 2026, plus 16 for compatibility.

Queue mode adds Redis, a shared database and one process per worker, so try the lighter option first. In regular mode n8n puts no limit on concurrent production executions, and the [concurrency page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/control-concurrency) says too many can thrash the event loop. Setting `N8N_CONCURRENCY_PRODUCTION_LIMIT` queues the excess inside one process. Move to queue mode once one process is the limit, not before.

## How a queued execution runs

A worker is the same n8n program started in a different role. The [docs](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) say each worker is its own Node.js instance that can handle several executions at once. All production executions run on workers. A webhook request still lands on the main instance or a webhook processor, which hands the execution over, and the docs warn that this can add overhead and latency.

Manual executions join them from n8n 3.0, in early access since 27 October 2026. The [breaking-changes page](https://docs.n8n.io/changelog/v30-breaking-changes) says they always run on workers in queue mode and removes `OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS`, so check how much memory your workers have. The path of one execution has six steps:

**One execution, from trigger to result**

1. Main takes the trigger. The main instance handles timers and webhook calls and generates a workflow execution without running it.
2. The ID goes to Redis. It passes the execution ID to Redis, which keeps the queue of pending executions.
3. A worker picks it up. The next available worker in the pool takes the message from Redis.
4. The worker loads the workflow. It uses the execution ID to read the workflow information from the database.
5. The worker saves the result. After the run it writes the results to the database and posts to Redis that the execution has finished.
6. Main is told. Redis notifies the main instance.

## Set up a main, a worker and Redis

The [n8n-hosting repository](https://github.com/n8n-io/n8n-hosting/blob/main/docker-compose/withPostgresAndWorker/docker-compose.yml) has a reference stack with Postgres, Redis, a main instance, one worker and a task runner sidecar for each. The excerpt below is trimmed from it, with the omitted parts marked. The file also sets `OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true`, which the [breaking-changes page](https://docs.n8n.io/changelog/v30-breaking-changes) lists as removed, so we left that line out.

Every process needs the same `N8N_ENCRYPTION_KEY`, because the [queue mode page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) says workers need the main instance's key to read credentials stored in the database. Each worker also needs its own task runner sidecar, which is why the file pairs `n8n-worker` with `n8n-worker-runner`, as the [task runner page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/set-up-task-runners) requires. Outside Compose you start a worker with `n8n worker`, and the docs' Docker form is `docker run --name n8n-queue -p 5679:5678 n8nio/n8n worker`.

````yaml
x-shared: &shared
  restart: always
  image: docker.n8n.io/n8nio/n8n:${N8N_VERSION}
  environment:
    - DB_TYPE=postgresdb
    - DB_POSTGRESDB_HOST=postgres
    - EXECUTIONS_MODE=queue
    - QUEUE_BULL_REDIS_HOST=redis
    - QUEUE_HEALTH_CHECK_ACTIVE=true
    - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY}
    - N8N_RUNNERS_MODE=external
    - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN}
    - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
  # ... database settings, volume and depends_on omitted

services:
  # ... x-runner, postgres, redis, n8n and n8n-runner omitted
  n8n-worker:
    <<: *shared
    command: worker
    depends_on:
      - n8n

  n8n-worker-runner:
    <<: *runner
    environment:
      - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN}
      - N8N_RUNNERS_TASK_BROKER_URI=http://n8n-worker:5679
    depends_on:
      - n8n-worker
````

1. Copy the `docker-compose/withPostgresAndWorker` folder from the n8n-hosting repository.
2. Change the default users, passwords and tokens in its `.env` file before you start, as the [README](https://github.com/n8n-io/n8n-hosting/blob/main/docker-compose/withPostgresAndWorker/README.md) warns. The compose file also reads `N8N_VERSION`, `ENCRYPTION_KEY` and `RUNNERS_AUTH_TOKEN`, so set those too.
3. Run `docker compose up -d`.
4. Check the worker from another container on the same Docker network. With `QUEUE_HEALTH_CHECK_ACTIVE=true`, its `/healthz/readiness` endpoint on port 5678 says whether the database and Redis connections are ready.
5. Publish a workflow with a Webhook trigger and call its production URL. The execution should run on the worker, not on main.

## Concurrency, Redis and timeouts

A worker runs ten jobs in parallel unless you pass the `concurrency` flag, as in `n8n worker --concurrency=5`. n8n recommends 5 or higher. The [queue mode page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) warns that low values with a large number of workers can exhaust the database connection pool, which leads to processing delays and failures.

One variable sits above the flag. `N8N_CONCURRENCY_PRODUCTION_LIMIT` is -1 by default, and in queue mode n8n takes the limit from it when it holds any other value. Otherwise it falls back to the flag or its default, says the [concurrency page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/control-concurrency).

Measure before you add workers. The docs report up to 220 executions per second on one 4 GB instance, but that run used only a Webhook and an Edit Fields node, so your workflows will differ. For a managed Redis, `QUEUE_BULL_REDIS_TLS` turns on TLS, and `QUEUE_BULL_REDIS_CLUSTER_NODES` switches n8n to a Redis Cluster client that ignores the host and port.

**Figures from n8n's scaling pages**

- **220** executions per second the docs report for one 4 GB instance running a Webhook and an Edit Fields node (Source: [n8n Docs: Measure performance](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/measure-performance), read 2026-11-04)
- **10** jobs a worker runs in parallel by default (Source: [n8n Docs: Enable queue mode](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode), read 2026-11-04)
- **5** the lowest worker concurrency n8n recommends (Source: [n8n Docs: Enable queue mode](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode), read 2026-11-04)
- **64 MiB** the largest webhook response a worker relays through Redis by default (Source: [n8n Docs: Queue mode environment variables](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/queue-mode), read 2026-11-04)

| Variable | Default | What it does |
| --- | --- | --- |
| `QUEUE_BULL_REDIS_HOST` | `localhost` | The Redis host |
| `QUEUE_BULL_REDIS_PORT` | `6379` | The Redis port |
| `QUEUE_BULL_REDIS_DB` | `0` | The Redis database |
| `QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD` | `10000` | How long, in ms, n8n waits while Redis is unavailable before it exits |
| `QUEUE_WORKER_LOCK_DURATION` | `60000` | The lease, in ms, that a worker holds on a message |
| `QUEUE_WORKER_LOCK_RENEW_TIME` | `10000` | How often, in ms, a worker renews that lease |
| `QUEUE_WORKER_STALLED_INTERVAL` | `30000` | How often, in ms, a worker checks for stalled jobs, with 0 for never |
| `N8N_GRACEFUL_SHUTDOWN_TIMEOUT` | `30` | Seconds a worker gets to finish its jobs before the process ends |
| `QUEUE_HEALTH_CHECK_ACTIVE` | `false` | Turns on the worker's health check endpoints |

## Binary data and large webhook responses

The [queue mode page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) says n8n does not support queue mode with binary data stored on the filesystem. The docs then point two ways. The [handle binary data page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/handle-binary-data) says to switch to `database`. The queue mode page points to S3 external storage for workflows that persist binary data. Both appear in the table.

The new major version changes the defaults under you. It removes the in-memory `default` mode, and the [breaking-changes page](https://docs.n8n.io/changelog/v30-breaking-changes) says an instance that still uses it switches to `filesystem` on upgrade. The [binary data variables page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/binary-data) still lists `default` as the default, so set `N8N_DEFAULT_BINARY_DATA_MODE` yourself.

A webhook response travels from the worker back to main inside a Redis message. The `N8N_WEBHOOK_RESPONSE_RELAY_SIZE_MAX` variable caps it at 64 MiB, and the docs advise budgeting about 1.5 times that in Redis memory for each response in flight. From n8n 2.34.0, setting `N8N_WEBHOOK_RESPONSE_RELAY_OFFLOAD_ENABLED=true` on the workers stores a larger body in binary data storage instead of failing the node. Upgrade every main and webhook instance first, because an older one hands the client the storage reference instead of the body.

> **Picking a binary data mode**
>
> Without a Business or Enterprise license, database is the only mode in the table that works with several workers, so start there. Move to S3 or Azure when files or responses grow. The docs recommend both for large webhook responses because they stream the body.

| Mode | With queue mode | Notes |
| --- | --- | --- |
| `filesystem` | Not supported | The queue mode page says n8n does not support it |
| `database` | Named by the handle binary data page | `N8N_BINARY_DATA_DATABASE_MAX_FILE_SIZE` defaults to 512 MiB and cannot exceed 1024, the limit of a database column |
| `s3` | Named by the queue mode page | Self-hosted Business or Enterprise with an active license key, and a bucket lifecycle rule because n8n leaves pruning to S3 |
| `azure` | Recommended for large responses | The same license rule as S3, and a lifecycle policy on the container for pruning |
| `default` | Removed in n8n 3.0 | Kept binary data in memory |

## Webhook processors and the load balancer

Webhook processors are an optional layer that scales incoming requests. You start one with `n8n webhook` and set `EXECUTIONS_MODE=queue` on it too. It listens on the same port as main, 5678 by default, behind a load balancer. The [docs](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) advise against putting the main instance in that pool, because heavy load there degrades the editor.

Set `N8N_WEBHOOK_URL` on the main instance to your public webhook URL. It is available from n8n 2.30.0. The older `WEBHOOK_URL` still works as an alias, but the [endpoints page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/endpoints) marks it deprecated from 2.35.0, with a warning in the log at startup. To stop main from handling production webhooks at all, set `N8N_DISABLE_PRODUCTION_MAIN_PROCESS=true` and keep main out of the webhook pool.

| Path | Route it to | What it carries |
| --- | --- | --- |
| `/webhook/*` | The webhook processor pool | Webhook trigger node endpoints |
| `/webhook-waiting/*` | The webhook processor pool | Human-in-the-loop endpoints of send-and-wait nodes, such as the Slack node |
| `/webhook-test/*` | The main instance | The default URL for manual executions |
| Everything else | The main instance | The internal API and the editor files |

## Multi-main for high availability

A single main instance does two jobs. It handles regular tasks such as the API, the UI and webhooks, and at-most-once tasks such as timers, pollers and pruning. Multi-main runs several main instances for high availability. The [docs](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) split the roles into followers for regular tasks and one leader for both kinds, and a follower takes over if the leader becomes unavailable.

- It is a self-hosted Enterprise feature and is not available on n8n Cloud.
- Every main runs in queue mode, connects to Postgres and Redis and sets `N8N_MULTI_MAIN_SETUP_ENABLED=true`.
- All main and worker processes run the same n8n version.
- The mains sit behind a load balancer with sticky sessions.
- The leader key lives 10 seconds and the leader check runs every 3 by default, set with `N8N_MULTI_MAIN_SETUP_KEY_TTL` and `N8N_MULTI_MAIN_SETUP_CHECK_INTERVAL`.

## What n8n's team and the n8n Helm chart say about running at scale

On 9 June 2026 the n8n team [announced on X](https://x.com/n8n_io/status/2064271339179897307) that n8n now supports OpenTelemetry natively. Its argument is that workflows now run payments, support, CRM syncs and AI agents, so a failure deserves the visibility of any other service. With workers spread across machines, traces give you one place to follow each execution.

n8n's [OpenTelemetry page](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/opentelemetry) says n8n can export workflow and node execution traces over OTLP to an OpenTelemetry collector. `N8N_OTEL_ENABLED` is off by default and exists from n8n 2.19.0, and `N8N_OTEL_TRACES_INCLUDE_NODE_SPANS` decides whether node spans are included.

For Kubernetes, the [n8n Helm chart](https://github.com/8gears/n8n-helm-chart) that 8gears maintains on GitHub maps these pieces onto a cluster. Its README says the chart spawns two worker instances, set with `scaling.worker.replicaCount`, and spawns no Redis server by default. Turning on `scaling.webhook.enabled` stops the main instance from processing webhooks.

> When something breaks, you deserve the same visibility you'd have for any other service.
>
> n8n.io, n8n's official account, [X](https://x.com/n8n_io/status/2064271339179897307) (read 2026-11-05)

[![n8n.io (@n8n_io) on X, 9 June 2026. n8n now supports OpenTelemetry natively. Your workflows aren't side projects anymore, they're production systems running payments, support, CRM syncs, and AI agents. When something breaks, you deserve the same visibility you'd have for any other service.](https://mindket.com/blog/shots/x-n8n-io-opentelemetry.webp?v=2c964b5a2ee4)](https://x.com/n8n_io/status/2064271339179897307)

n8n.io on X, 9 June 2026

> A screenshot of X's own embed of the post, taken on 5 November 2026, with the time in UTC. X cuts the post short with Show more. Select it to open the post on X.

## Common mistakes

- A worker with its own encryption key. The docs say the key of the main instance must reach every worker and webhook processor, or they cannot read the stored credentials.
- Leaving `EXECUTIONS_MODE=queue` off a webhook processor. The docs say webhook processes rely on Redis and need the variable set too.
- Still setting `OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS` or `QUEUE_WORKER_MAX_STALLED_COUNT`. The [breaking-changes page](https://docs.n8n.io/changelog/v30-breaking-changes) removes the first, and the second has had no effect since n8n 2.0. The variables page still lists both.
- Sharing one task runner sidecar between workers, or running a runners image of another version. Each worker needs its own sidecar, and the `n8nio/runners` image must match the `n8nio/n8n` image.
- Raising the Postgres image from 16 to 18 on an existing volume. The [README](https://github.com/n8n-io/n8n-hosting/blob/main/docker-compose/withPostgresAndWorker/README.md) says it stops with "FATAL: database files are incompatible with server", and it warns you to keep the `PGDATA` line in the file.
- Using Simple Memory for a chat agent in production on a queue-mode instance. The [Simple Memory page](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.memorybufferwindow) says it does not work there, so pick Redis Chat Memory or Postgres Chat Memory, as the [AI agent lesson](https://mindket.com/learn/n8n/n8n-ai-agent) shows.
- Pointing several workers at one event log file. When workers share a writable filesystem, give each process its own `N8N_EVENTBUS_LOGWRITER_LOGFULLPATH`, an absolute path that ends in `.log`, as the [log streaming page](https://docs.n8n.io/administer/observe-and-log/stream-logs-to-external-systems) explains.

## Try it yourself

- Bring up the reference stack with your own secrets, call a webhook workflow at its production URL and open the execution in the editor.
- Add `--concurrency=5` to the worker command and compare how many executions run at once.
- Stop the worker container, trigger the webhook once and note what the execution does until you start the worker again.
- Read the worker's `/healthz/readiness` from inside the Docker network, stop Redis and read it again.

## Next course: Dify

This is the last lesson of the n8n advanced course. The next course, [the Dify tutorial](https://mindket.com/learn/dify/dify-tutorial), builds AI apps and workflows in Dify, a platform made for LLM apps with a knowledge base and agents built in. To put your new n8n setup to work, pick a ready-made workflow from the [n8n workflow directory](https://mindket.com/automations/n8n) and import it as the [import guide](https://mindket.com/blog/import-n8n-workflow) shows.

## Check yourself

1. What does n8n need for queue mode besides the main instance and the workers?

   A. A shared network disk for binary data
   B. SQLite on every worker
   C. A load balancer in front of Redis
   D. Redis as the broker and a Postgres database

   Answer: D. Redis holds the queue and the database persists the data, so access to both is required, and a distributed setup over SQLite is not supported.

2. A worker cannot open credentials that the main instance saved. What do you check first?

   A. That it uses the same N8N_ENCRYPTION_KEY
   B. That QUEUE_BULL_REDIS_DB is 0
   C. That it runs with --concurrency=10

   Answer: A. The main instance key must be shared with every worker and webhook processor so they can read the stored credentials.

3. Which binary data mode does n8n not support in queue mode?

   A. database
   B. S3
   C. filesystem

   Answer: C. The queue mode page says n8n does not support queue mode with binary data stored on the filesystem.

4. You put webhook processors behind a load balancer. Which path stays on the main instance?

   A. /webhook/*
   B. /webhook-test/*
   C. /webhook-waiting/*

   Answer: B. The webhook and webhook-waiting paths go to the processor pool, while the test URL for manual executions stays on main.

## Frequently asked questions

### Does n8n queue mode need Redis and Postgres?

Yes. Redis keeps the queue of pending executions, and PostgreSQL holds the workflows, credentials and results that every process shares. The docs say a distributed setup over SQLite is not supported.

### How many workers do I need?

The docs give no formula. n8n recommends a worker concurrency of 5 or higher, and its own multi-instance benchmark used four workers and two webhook instances. Size yours from your own peak load.

### Is multi-main available without an Enterprise license?

No, a license is needed, and the docs list multi-main for self-hosted Enterprise only. n8n Cloud does not offer it, and queue mode with one main and several workers carries no such note.

### Where does binary data go in queue mode?

Use database mode, or S3 or Azure Blob storage on a self-hosted Business or Enterprise license, because filesystem mode is out. The in-memory default mode was removed too.

### Do workers need task runners for the Code node?

In external mode, yes, and the reference compose file shows the pairing: n8n-worker-runner serves n8n-worker, just as n8n-runner serves the main instance. Internal mode is deprecated.

### Where do manual test runs execute in queue mode?

They always run on workers now, and the OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS setting is gone. The test webhook URL still routes to the main instance.

## Sources

- [n8n Docs: Enable queue mode](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/enable-queue-mode) (read 2026-11-04)
- [n8n Docs: Queue mode environment variables](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/queue-mode) (read 2026-11-04)
- [n8n Docs: Control concurrency](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/control-concurrency) (read 2026-11-04)
- [n8n Docs: Measure performance](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/measure-performance) (read 2026-11-04)
- [n8n Docs: Handle binary data](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/handle-binary-data) (read 2026-11-04)
- [n8n Docs: Binary data environment variables](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/binary-data) (read 2026-11-04)
- [n8n Docs: Use external storage](https://docs.n8n.io/deploy/host-n8n/configure-n8n/scaling/use-external-storage) (read 2026-11-04)
- [n8n Docs: Choose your n8n database](https://docs.n8n.io/deploy/host-n8n/configure-n8n/choose-n8ns-database) (read 2026-11-04)
- [n8n Docs: Set up task runners](https://docs.n8n.io/deploy/host-n8n/configure-n8n/set-up-task-runners) (read 2026-11-04)
- [n8n Docs: v3.0 breaking changes](https://docs.n8n.io/changelog/v30-breaking-changes) (read 2026-11-04)
- [n8n-hosting repository: Postgres and worker compose file](https://github.com/n8n-io/n8n-hosting/blob/main/docker-compose/withPostgresAndWorker/docker-compose.yml) (read 2026-11-04)
- [n8n-hosting repository: Postgres and worker README](https://github.com/n8n-io/n8n-hosting/blob/main/docker-compose/withPostgresAndWorker/README.md) (read 2026-11-04)
- [n8n Docs: Simple Memory node](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.memorybufferwindow) (read 2026-11-04)
- [n8n Docs: Stream logs to external systems](https://docs.n8n.io/administer/observe-and-log/stream-logs-to-external-systems) (read 2026-11-04)
- [n8n Docs: Executions environment variables](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/executions) (read 2026-11-04)
- [n8n Docs: Endpoints environment variables](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/endpoints) (read 2026-11-05)
- [n8n Docs: OpenTelemetry environment variables](https://docs.n8n.io/deploy/host-n8n/configure-n8n/basic-configuration/use-environment-variables/opentelemetry) (read 2026-11-05)
- [n8n.io on X: n8n now supports OpenTelemetry natively, 9 June 2026](https://x.com/n8n_io/status/2064271339179897307) (read 2026-11-05)
- [8gears on GitHub: n8n Helm chart](https://github.com/8gears/n8n-helm-chart) (read 2026-11-05)

[Browse n8n workflows](https://mindket.com/automations/n8n)
