Skip to content
Skip to main content
An abstract visual metaphor of an n8n queue distributing jobs to parallel worker nodes through a message broker
9 min readBy Carlos Aragon

Scaling Self-Hosted n8n: When to Switch to Queue Mode

Default n8n runs the editor, your webhooks, and every workflow execution in one Node process. It's great right up until the UI crawls while jobs run and webhook triggers start dropping under load. The signal to move is simple — the main process pinned near 80% CPU — and the fix is queue mode: a main instance for the editor and webhooks, a Redis broker for the job queue, and dedicated worker processes on Postgres. Here's exactly when I flip it, and the setup I run.

The Night One n8n Process Couldn't Keep Up

I had a single n8n container quietly handling a client's lead pipeline — webhooks in from a couple of ad platforms, enrichment, a Postgres write, a notification out. Fine at ten leads an hour. Then a campaign went live and the webhooks came in bursts. The editor went unusable while runs were executing, a chunk of executions showed up as crashed or never-started, and a few leads simply never got processed. Nothing in the workflow logic was wrong. The box was just doing too many jobs in one process.

That is the whole story of outgrowing single-process n8n. In the default mainmode, one Node process receives the webhook, holds the editor session, and executes the workflow — all on the same event loop and the same CPU. A burst of triggers competes with the executions already running, and something has to give. Usually it's the thing you notice last: dropped webhooks.

The one-line diagnosis:

If your n8n editor gets slow while workflows are running, or webhook executions drop during traffic spikes, you haven't hit a bug — you've hit the ceiling of a single process. That's the queue-mode signal.

The Exact Signals I Watch Before Flipping to Queue Mode

I don't switch on vibes, and I don't switch too early — queue mode adds Redis and worker containers to babysit, so a small instance shouldn't pay that tax. These are the three signals that actually mean it's time:

  • The editor UI is sluggish or unresponsive specifically while executions are running — the tell that serving the editor and running jobs are fighting for the same process.
  • Webhook-triggered executions drop, time out, or show as "crashed" during bursts, even though the same workflow runs fine one at a time.
  • The main n8n process sits around 80% CPU under normal load, with no headroom for spikes.

If none of those are true, you don't need queue mode yet — you need a bigger box or a Postgres database, which is a cheaper move. But once any of them is your normal Tuesday, adding vCPUs only buys you weeks. Queue mode is the architectural fix because it separates the two jobs that are colliding.

What Queue Mode Actually Changes

Queue mode splits one process into three roles, and that split is the entire benefit:

ComponentJobScales by
Main instanceServes the editor, accepts webhooks, enqueues jobsStays light; one is usually enough
Redis brokerHolds the job queue between main and workersVertically / managed Redis
Worker(s)Pull jobs off Redis and execute the workflowsHorizontally — add more workers
PostgresPersists workflows, credentials, execution dataRequired — no SQLite

Now a webhook burst hits the main instance, which does the cheap thing — acknowledge and drop the job onto Redis — and returns immediately. The workers, running in their own processes, pull jobs and execute them in parallel. The editor never competes with a running workflow again, because the editor and the execution live in different processes. When the workers can't keep up, you add another worker container. That's horizontal scaling, and it's the thing a single process could never give you.

The Setup, Minus the Yak-Shaving

The migration is four moves, in this order. Do them in order — flipping EXECUTIONS_MODEbefore you're on Postgres just breaks things.

1. Get on Postgres first.Multiple workers can't share a SQLite file — it's unsupported, full stop. Point n8n at Postgres and confirm your existing workflows and credentials survived the move before you touch anything else.

2. Stand up Redisand hand n8n the connection. Redis is the queue; it's not optional in queue mode.

3. Set the main instance to queue mode and start workers. Same environment, different command:

# --- main instance (editor + webhooks) ---
EXECUTIONS_MODE=queue
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
QUEUE_BULL_REDIS_HOST=redis
QUEUE_BULL_REDIS_PASSWORD=***
# command: n8n start

# --- worker (one or more of these) ---
# same env as above, different command:
# command: n8n worker --concurrency=10

4. Scale workers by queue depth, not by guessing. Each worker runs a fixed number of executions at once (--concurrency). Watch how deep the Redis queue gets under real load: if jobs pile up faster than workers clear them, add a worker; if the queue is almost always empty, you're done. This is the same “deterministic state, measured, not assumed” discipline I lean on for choosing Postgres vs Redis for agent memory.

The official reference for the flags and the broker setup is n8n's queue-mode docs, and it's worth reading before you commit env vars to a compose file.

The Mistakes That Cost Me Time

  • Leaving SQLite in place "just to test" — workers silently fought over the file and executions vanished. Postgres is step zero, not a later optimization.
  • One giant worker with huge concurrency instead of two modest ones. A memory-heavy execution can take the whole worker down; more small workers means a bad job kills one lane, not the highway.
  • Forgetting the workers need the same encryption key and credentials env as main — otherwise they can't decrypt credentials and every execution fails in a confusing way.
  • Not watching queue depth. Without that metric you're scaling blind: either overprovisioned and paying for idle workers, or underprovisioned and quietly building a backlog.

Most of these come from treating queue mode like a config flag instead of a small distributed system. It is a distributed system — a modest one, but real — and the failure modes are the boring distributed-systems ones: shared state, decryption keys, and a queue you forgot to watch. I wrote about the broader version of that lesson in why my n8n agents started failing silently.

Queue Mode Is Not the Same as High Availability

Worth being honest about the ceiling. Multiple workers give you execution redundancy — one dies, the others keep clearing the queue — and you can put several webhook processes behind a load balancer. That's a real reliability win. But the main instance, Redis, and Postgres are each still a single point of failure until you make them redundant on their own. Queue mode is the prerequisite for high availability, not the whole thing. If your automations are load-bearing for revenue, plan for a managed or replicated Redis and Postgres next, and more than one main.

For most self-hosters, though, the jump from one process to main-plus-workers is the 10x that matters. It's the difference between an instance that falls over during your best sales day and one that just spins up another worker and keeps going. If you're building the automations that sit on top of that infrastructure, my practical n8n build walkthrough and my notes on keeping autonomous loops from torching your budget are the natural next reads.

The Short Version

  • Single-process n8n runs the editor, webhooks, and executions on one CPU — it works until they collide.
  • Switch to queue mode when the UI lags during runs, webhooks drop under bursts, or the main process pins near 80% CPU.
  • Queue mode = main instance + Redis broker + dedicated workers, backed by Postgres. SQLite is a hard no.
  • Do it in order: Postgres first, then Redis, then EXECUTIONS_MODE=queue, then workers.
  • Scale by watching Redis queue depth; prefer several modest workers over one giant one.
  • Queue mode enables high availability but isn't HA by itself — main, Redis, and Postgres still need their own redundancy.

Need n8n That Won't Fall Over on Your Best Day?

I design and run production n8n on queue mode — Redis, dedicated workers, Postgres, and monitoring wired in so a traffic spike scales a worker instead of dropping your leads. If your automations are load-bearing and you want them to stay up, let's talk.

Related Posts