n8n in production

Why your self-hosted n8n gets slower as you add workers

Adding workers to a queue-mode instance is the standard answer to a backlog, and past a certain point it makes the backlog worse. Almost everything n8n does ends in a database write, and every worker you add competes for the same connection pool.

Why does self-hosted n8n get slower when you add workers? Because the bottleneck is usually the database rather than CPU. Each execution writes to Postgres several times, at start, on progress and at completion, and every worker holds connections from a fixed pool. Add workers without raising pool and connection limits and the workers spend their time waiting on the database instead of running workflows. Fix the write volume and the pool arithmetic before adding capacity.

The symptom is consistent enough to diagnose from a description. Executions queue up. Somebody triples the worker count. Throughput improves for an afternoon and then gets worse than it started, with executions that used to finish in seconds sitting in a running state for minutes. CPU on every box looks fine. That last detail is the tell.

Every execution is several database writes

n8n keeps execution state in the database rather than in memory, which is the right decision for durability and the reason it does not lose your run when a worker restarts. The cost is write volume. A single execution touches the executions table when it starts, again as it progresses, and again when it finishes, and it stores the data that moved between nodes along the way.

That last part is where estates get into trouble quietly. A workflow that moves a few hundred records per run stores those records as execution data. Multiply by a few thousand runs a day and the table grows faster than anyone predicted, and every query against it gets slower, including the ones n8n itself runs to pick up the next job.

The connection pool arithmetic nobody does upfront

Three numbers have to agree with each other, and by default they do not.

Six workers at a generous concurrency, plus the main process, plus whatever else shares the database, exhausts a default Postgres limit easily. When it does, processes wait on a free connection rather than erroring, which is why the dashboard shows work in progress and nothing progressing. The counter-intuitive fix is often fewer workers with higher per-worker concurrency, sized against a pool you have actually counted.

Silent failure costs more than downtime

An outage gets noticed within the hour. A workflow that stops producing output while reporting success can run wrong for weeks. Four patterns account for most of what we have seen.

  1. No error workflow attached. A workflow with nothing set in its error workflow slot fails into the execution log, and the execution log is not a place anyone visits daily. Set one globally, route it to a channel a human reads, and do it before you build anything else.
  2. An API that returns 200 with an empty body. Plenty do, particularly when a token has expired or a filter matched nothing. The workflow continues happily over zero items and reports success. The guard is an explicit check on item count, not a trust in the status code.
  3. Sub-workflows swallowing errors. A called workflow that handles its own failure can return control to the parent as though everything worked. Decide deliberately which layer owns the failure.
  4. Execution pruning hiding the evidence. Aggressive retention settings keep the database healthy and delete the record of the failure you are trying to investigate. Keep failed executions longer than successful ones.

Timeouts are usually a shape problem

Workflows that time out are rarely slow because a single node is slow. They are slow because one execution is doing work that belongs to many. A run that pulls 20,000 records, loops over each one and calls an API per record is a batch job pretending to be a workflow, and it will keep hitting whatever ceiling you raise.

The fix that holds is to split the shape rather than raise the limit. One workflow fetches and queues the work in pages. A second processes a page and finishes. Each execution then stays short, failures retry a page rather than the whole run, and the execution log stops storing a payload the size of the source system. Raising the timeout instead buys a week and returns the same problem with a larger blast radius.

What we changed on our own stack

Digiton runs its operations on owned infrastructure, and a large share of what used to sit in a workflow canvas now runs as plain scheduled jobs at the operating system level, with per-job log files and state on disk. That decision came from the silent failure problem rather than from performance. A weekly reporting workflow we run for a US email-marketing agency client stopped producing output without raising anything, and the durable fix was moving it somewhere with a log we tail and an alert that fires on absence rather than on error.

The rule we settled on: a visual canvas is worth it when a non-engineer genuinely needs to read the logic or change a branch. When the workflow is a script wearing 30 nodes, it should be a script.

Fix in this order

  1. Attach an error workflow globally and route it somewhere a person reads. This is an hour of work and it is the highest-value hour in the list.
  2. Turn on execution pruning with a longer retention for failures, and check the size of the executions table before and after.
  3. Count your real connection limit, then set worker count and per-worker concurrency to fit inside it with headroom.
  4. Give the database its own resources rather than sharing a box with the workers.
  5. Stop storing large payloads in execution data. Pass references and fetch inside the node that needs the content.
  6. Only then add workers, and measure whether throughput actually moved.

One planning note on queue mode: which parts of a highly available multi-instance setup are covered by which licence tier has moved between releases. Confirm the current terms against your own version before you design around them.

When n8n is the wrong tool

Sub-second latency in a user-facing request path, anything requiring transactional guarantees across systems, and very high volume single-purpose pipelines all belong in application code. n8n earns its place in the middle band: real business logic across many services, changing often enough that a deployment cycle per change would be painful.

If you are weighing the platform itself rather than tuning it, the comparison work sits in the Zapier to n8n migration breakdown and in our n8n and Make comparison.

Frequently asked questions

Why does adding more n8n workers make executions slower?

Because the constraint is usually the database, not CPU. Each execution writes to Postgres several times and each worker holds connections from a fixed pool. Once worker count times per-worker concurrency exceeds the available connections, processes wait for a free connection instead of erroring, so work appears to be running while nothing progresses.

Why do n8n workflows fail silently?

Four common causes. No error workflow attached, so failures land only in the execution log. An API returning 200 with an empty body, so the workflow succeeds over zero items. Sub-workflows handling their own errors and returning control as if everything worked. And aggressive execution pruning deleting the evidence before anyone investigates. Set a global error workflow first, then add an explicit item-count check.

How do I stop the n8n executions table from growing out of control?

Turn on execution pruning, keep failed executions longer than successful ones, and stop storing large payloads as execution data. Pass a reference and fetch the content inside the node that needs it. Give the database its own resources rather than sharing a host with the workers.

What are the right worker and concurrency settings for n8n?

There is no universal number. Count the maximum connections your Postgres instance accepts, subtract everything else connecting to it, then size worker count and per-worker concurrency to fit inside that with headroom. Fewer workers at higher concurrency often outperforms many workers competing for the same pool.

Is n8n queue mode available on the free self-hosted version?

Queue mode is a configuration choice, but which parts of a highly available multi-instance setup fall under which licence tier has changed between releases. Confirm the current terms against the version you are running before designing an architecture that depends on it.

When should a workflow not live in n8n at all?

When it sits in a user-facing request path needing sub-second latency, when it requires transactional guarantees across systems, or when it is a very high volume single-purpose pipeline. n8n earns its place on business logic that spans many services and changes often enough that a deployment per change would hurt.

Does Digiton run n8n in production?

Digiton runs its own operations on owned infrastructure and uses both workflow canvases and plain scheduled jobs, choosing between them per workload. A large share of recurring internal jobs run as scheduled scripts with per-job logs, a decision driven by silent failure risk rather than performance.

Related

Zapier to n8n migrationn8n automation answersn8n vs MakeAutomation cost calculatorAI automation agency for enterprise

Want the number before the call?

The cost calculator gives you a build band, a monthly running cost and a payback range from our published 2026 price list. No email needed to see it.

Open the AI automation cost calculator

Tell us the operation, get a scoped answer

One line about the work you would hand over. We reply within one working day with the band it falls in and whether it is worth building at your volume.

Rather book directly? Book a discovery audit or mail contact@digiton.ai.