n8n runs happily as a single process until the day an upstream system decides to send everything at once. For the operations team at a marketplace we will call Fernhill Goods, that day arrived when their payment provider retried three hours of failed webhooks in six minutes and the n8n instance that turned orders into warehouse tasks fell an hour behind. This post is the DevOps engineer's account of moving n8n into queue mode on MassiveGRID PaaS, which is built on Virtuozzo Application Platform (formerly Jelastic), so that bursts become a scaling event rather than an incident.

What a single n8n process can and cannot do

In its default mode n8n runs webhooks, the editor and workflow executions in one Node.js process. Executions are asynchronous, but they share one event loop and one memory space, so a burst of incoming webhooks queues inside the process and everything, including the editor, slows down. Adding CPU helps to a point. Beyond that, the fix n8n itself recommends is queue mode: the main instance accepts webhooks and pushes executions onto a Redis queue, and separate worker processes pull from the queue and run them. Capacity then scales with the number of workers.

The n8n package on MassiveGRID PaaS installs n8n with a PostgreSQL database, which is already the right foundation: queue mode requires a real database rather than SQLite, and PostgreSQL is what the package provides. What remains is Redis, workers and the rules that add workers when they are needed.

First line of defence: vertical scaling

Before touching the topology, the engineer raised the n8n node's dynamic cloudlet ceiling. On the platform every container grows in cloudlets, 128 MiB of RAM plus 400 MHz of CPU each, up to a limit you set, without a restart. The n8n node had been running at 4 cloudlets with a ceiling of 8; the ceiling went to 24. That alone would have absorbed the first minutes of the burst, because n8n's memory and CPU would have expanded as executions piled up, and the hourly charge would have risen only for the hours the extra cloudlets were in use.

Vertical scaling is the reason the engineer did not rush. It buys time and it is free until used. But a single process still has a ceiling of one event loop, so the second step was structural.

Adding Redis and workers to the environment

From the topology wizard the engineer added a Redis node to the n8n environment and a second Node.js layer, named workers, running the same n8n image with the command n8n worker. The main n8n node and the workers share the environment's variables: EXECUTIONS_MODE=queue, the Redis host (the container hostname, reachable over the free internal network), the PostgreSQL connection, and the same N8N_ENCRYPTION_KEY so workers can decrypt credentials. Because the layer is on the internal network, the Redis node needs no public IP and the container firewall keeps it unreachable from outside.

EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis.<env>.<platform domain>
QUEUE_BULL_REDIS_PORT=6379
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres.<env>.<platform domain>
N8N_ENCRYPTION_KEY=<same value on main and workers>
QUEUE_HEALTH_CHECK_ACTIVE=true

The workers layer started with two nodes at 4 reserved cloudlets and a ceiling of 12 each. The main node now only accepts webhooks and serves the editor, so its own consumption dropped.

Letting the platform add workers

The key configuration is an automatic horizontal scaling trigger on the workers layer. The engineer set it to add one worker when the layer's average CPU exceeds 60% for two minutes, up to eight workers, and to remove one when average CPU is below 20% for ten minutes, down to two. The platform evaluates the layer average every minute, creates the new container on a different physical host, and because the layer is in stateless mode (workers have no local state worth copying) the new node starts from the base image with the environment variables already set and joins the queue within a minute.

The choice of stateless mode matters for speed: a stateless node is created from the template rather than cloned from the master, so it is ready sooner. Workers do not need custom files, so nothing is lost. The main n8n node, which holds custom nodes and the editor's static assets, stays in stateful mode and is not horizontally scaled at all.

A second trigger was set on the Redis node's memory, not to scale it but to email a load alert at 80%, because a queue that fills faster than eight workers can drain it is a sign the ceiling needs raising rather than something to discover in the morning.

The retry storm, replayed

Two months later the payment provider did it again: roughly 10,000 webhooks over six minutes on a Tuesday afternoon. The sequence looked like this.

MinuteWhat happenedWorkers
0Webhooks arrive; main node acknowledges each in milliseconds and enqueues2
1Workers hit their vertical ceilings; layer average CPU passes 60%2
3First trigger fires; third worker joins the queue3
5 to 9Trigger fires every two minutes as load stays high6
14Queue drains to zero; warehouse tasks fully caught up6
25Average CPU below 20% for ten minutes; removal begins5
65Back to baseline2

No webhook was lost, because the main node never had to do anything slower than write to Redis. The extra four workers ran for about an hour. At MassiveGRID's published rate of $0.003372 per cloudlet-hour, four workers at 12 cloudlets for one hour cost about sixteen cents. The previous incident had cost a warehouse shift of manual reconciliation.

Making it robust

Three additions turned a working setup into one the team trusts.

Frequently Asked Questions

Does queue mode change how workflows are built?

No. Workflows, credentials and nodes are identical; only the execution engine changes. Two things to check: every worker must have the same encryption key, and any workflow that reads or writes local files needs shared storage or should be rewritten to use a binary data store, since executions may run on any worker.

Why stateless mode for the workers layer?

Stateless nodes are created from the base image, which is faster than cloning the master container, and workers hold no custom files worth copying. Environment variables are applied to every node in the layer, so a fresh worker has everything it needs. The main n8n node, which does carry custom nodes and settings, stays stateful.

How is this different from running n8n queue mode on a VPS?

Everything about queue mode is the same; what changes is who adds the workers. On a VPS you provision capacity for the burst in advance or script container scaling yourself. On MassiveGRID PaaS a trigger evaluated every minute adds and removes worker containers on separate hosts, each also growing vertically in cloudlets, and you are billed hourly for what ran.

n8n that scales with the queue

The n8n package on MassiveGRID PaaS installs n8n with PostgreSQL in one click. Add Redis and a workers layer from the topology wizard, set a scaling trigger, and pay per cloudlet-hour for the bursts. Free 14-day trial, no credit card.

n8n on PaaS

Further Reading