Skip to content
SelfHostBR, home page
Infra

n8n queue mode with Redis and workers in Docker Compose

Turn on n8n queue mode with Redis, PostgreSQL and workers in Docker Compose: a complete compose.yaml, how to scale workers and how much memory each one uses.

MMarlon Published on 7 min read
On this page

Short answer: in queue mode, the main n8n instance receives triggers and webhooks and puts each execution in a queue in Redis; worker processes pick executions up from the queue and run them. You turn it on with EXECUTIONS_MODE=queue on the main instance and on the workers, all connected to the same Redis and the same PostgreSQL.

When it is worth it

  • Many executions at the same time, or heavy workflows that freeze the interface.
  • You want to scale by adding workers, including on other machines.

For personal use, a regular instance is enough, and queue mode just adds parts to maintain. The documentation points out that queue mode with SQLite is not recommended and that it does not support binary data on the filesystem: for that, use S3 storage (docs).

The compose.yaml

Create the .env file with the PostgreSQL user, password and database and the N8N_ENCRYPTION_KEY, as in the n8n with PostgreSQL guide. The key must be the same on every instance, or the workers cannot read the credentials.

x-n8n: &n8n
  image: n8nio/n8n:stable
  restart: always
  environment:
    DB_TYPE: postgresdb
    DB_POSTGRESDB_HOST: postgres
    DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
    DB_POSTGRESDB_USER: ${POSTGRES_USER}
    DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
    N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
    EXECUTIONS_MODE: queue
    QUEUE_BULL_REDIS_HOST: redis
    QUEUE_HEALTH_CHECK_ACTIVE: "true"
    GENERIC_TIMEZONE: Europe/Berlin
    TZ: Europe/Berlin
  depends_on:
    postgres:
      condition: service_healthy
    redis:
      condition: service_healthy

services:
  postgres:
    image: postgres:18
    restart: always
    environment:
      - POSTGRES_USER
      - POSTGRES_PASSWORD
      - POSTGRES_DB
      - PGDATA=/var/lib/postgresql/data
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 10

  redis:
    image: redis:8-alpine
    restart: always
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 5s
      retries: 10

  n8n:
    <<: *n8n
    ports:
      - "127.0.0.1:5678:5678"
    volumes:
      - n8n_data:/home/node/.n8n

  n8n-worker:
    <<: *n8n
    command: worker --concurrency=5

volumes:
  db_data:
  redis_data:
  n8n_data:
  • The x-n8n block avoids repeating the configuration: the main instance and the worker use the same image, the same database, the same Redis and the same key.
  • The worker is the same n8n image with the worker command. --concurrency=5 sets how many executions each worker runs in parallel (the default is 10). The documentation recommends 5 or more, because many workers with low concurrency exhaust the database connections.
  • Redis publishes no port: it stays on the internal Compose network, without a password. If it runs on another machine, set QUEUE_BULL_REDIS_PASSWORD and restrict access.
  • For HTTPS, put a reverse proxy in front of the main instance, as in the Traefik guide.

Start it and check that the workers are working

docker compose up -d
docker compose logs -f n8n-worker

When you trigger a production workflow (a published webhook, for example), the worker log shows:

Worker started execution 1 (job 1)
Worker finished execution 1 (job 1)

With QUEUE_HEALTH_CHECK_ACTIVE, each worker answers a readiness check that verifies the connection to the database and Redis:

docker compose exec n8n-worker wget -qO- http://localhost:5678/healthz/readiness
# {"status":"ok"}

Scaling: more workers

docker compose up -d --scale n8n-worker=2

With two workers, the queue spreads executions between them: 20 simultaneous calls to a webhook are split across the two with no extra configuration. If executions wait in the queue, add workers. If the database complains about connections, reduce the number of workers and raise each one’s concurrency.

The Settings > Workers screen, which shows workers in the interface, is available only on self-hosted Enterprise, and so is multi-main (more than one main process, for high availability). On the Community edition, follow the workers through the logs and docker stats. The docs page “Compare editions” lists queue mode as included in Community Edition, but the pricing page lists it among the Business features, so check the licence before you count on it.

How much memory to reserve

Typical use with two workers, right after a burst of 20 calls to a simple workflow:

ContainerMemory
n8n (main)~300 MiB
each worker300 to 460 MiB
PostgreSQL~70 MiB
Redis~9 MiB

With one worker, the whole stack sits near 700 MiB under light load. A 2 GB VPS fits the main instance and one worker with room for simple workflows; for each extra worker, count another 0.5 to 1 GB, and much more if the workflows use AI, large files or the Code node. Compare plans in how much it costs to host n8n or estimate in the calculator.

Frequently asked questions

What is n8n queue mode?

It is the mode where the main instance receives triggers and webhooks and puts executions in a Redis queue, and separate worker processes pick up and run those executions.

Can I use queue mode with SQLite?

The documentation does not recommend it. Use PostgreSQL together with Redis.

How many executions does a worker run at once?

The default is 10, adjustable with n8n worker --concurrency. The documentation recommends 5 or more.

How do I add more workers?

In Docker Compose, run docker compose up -d --scale n8n-worker=2 (or the number you want). All of them need the same Redis, the same database and the same encryption key.

M

Written by

Marlon

I like automation and write here what I learn building automations with n8n. Spotted a mistake or an outdated detail? Let me know.

Keep reading