# n8n Webhooks, Queues, and Execution Retention Explained

- Link: https://offshorehosting.pk/n8n-webhooks-queues-execution-retention/
- Published: 2026-10-25T10:40:00+00:00
- Author: admin

# n8n Webhooks, Queues, and Execution Retention Explained

Three settings decide whether a busy n8n instance stays responsive or slowly grinds
to a halt: how webhooks are received, whether executions run in queue mode, and 
how long execution history is kept. They are connected. A webhook that arrives during
a traffic spike has to be accepted, queued, executed, and recorded — and if any 
part of that chain is misconfigured, you get lost webhooks, stuck jobs, or a database
that grows until the disk fills.

This guide explains each piece in plain terms, the defaults that catch people out,
and the settings worth changing before your instance gets busy.

## How a webhook execution works

A webhook is an HTTP request sent to n8n by another service — a form submission,
a payment notification, a new order. The webhook node in your workflow defines the
URL and the HTTP method. When a request arrives, n8n starts an execution of that
workflow.

There are two ways n8n can handle that moment:

 * **Respond immediately, then execute.** Some webhook setups acknowledge the request
   straight away and run the workflow afterwards. The sender gets a fast response,
   and a slow workflow does not hold the connection open.
 * **Execute, then respond.** Other setups run the workflow first and return the
   workflow’s output as the HTTP response. This is useful when the sender needs 
   a result, but a slow workflow can time out the sender’s request.

Which behaviour you get depends on the webhook node’s response settings. Before 
you design a workflow around a webhook, check what the sending service expects: 
a fast acknowledgement, or a meaningful response body. A payment provider that retries
on timeout will happily send the same event three times if your workflow takes too
long to answer — so design for duplicates, for example by checking whether the event
has already been processed before acting on it.

### Why webhooks fail in production but work in testing

The most common webhook complaint is that everything works locally and fails on 
the server. The usual cause is the public URL. Behind a reverse proxy, n8n may generate
webhook URLs based on its internal address instead of your public domain. Set the
public webhook URL explicitly in your environment (`WEBHOOK_URL`, or `N8N_WEBHOOK_URL`
in older versions) to your full public address, for example `https://n8n.yourdomain.
com/`, and make sure your proxy passes the original host and protocol headers through.
Also confirm the webhook URL is reachable from the internet — a firewall rule or
a missing DNS record will silently drop every incoming event.

## Regular mode vs queue mode

By default, n8n runs in **regular mode**: a single process handles the editor, receives
webhooks, runs schedules, and executes workflows. That is fine for light use. It
becomes a problem under load, because one long or heavy execution can block others,
and if the process crashes or runs out of memory, every active workflow dies with
it.

**Queue mode** separates the work. The main process handles the editor, webhook 
reception, and scheduling, while separate worker processes execute the workflows.
Jobs pass between them through Redis. If a worker crashes, the queued jobs wait 
and are picked up when a worker returns, rather than being lost with the crashed
process.

To enable queue mode, the key settings are:

    ```bash
    EXECUTIONS_MODE=queue
    QUEUE_BULL_REDIS_HOST=redis
    QUEUE_BULL_REDIS_PORT=6379
    ```

You then start worker processes alongside the main instance:

    ```bash
    n8n start        # main process: editor, webhooks, scheduling
    n8n worker --concurrency=10   # worker: executes workflows
    ```

A few rules that matter:

 * **Main and workers must run the same n8n version and the same encryption key**,
   or credentials will break in confusing ways.
 * **Redis becomes a core dependency.** If Redis goes down, no new executions will
   start. Run it with persistence enabled and monitor it as a critical service, 
   not an optional extra.
 * **Use PostgreSQL, not SQLite, in queue mode.** SQLite locks under concurrent 
   write load, which is exactly what queue mode creates.
 * **Set the same retention and execution settings on every node**, so no container
   works from a different idea of the rules.

Queue mode is not magic: it adds Redis as a moving part. For a handful of low-volume
workflows, regular mode with a sensible retention policy is simpler and perfectly
adequate.

## Execution retention: the setting that fills your disk

Every time a workflow runs, n8n can save the execution: its status, the data that
passed through each node, and any error. That history is invaluable for debugging—
you can open a failed run and see exactly which node received what. It is also the
fastest way to fill a database.

By default, n8n keeps a lot. A workflow that runs every minute produces over 40,000
executions a month. A busy sync workflow can produce thousands a day. The default
count cap (10,000 executions) sounds generous until a single chatty workflow hits
it in five days, and then older history starts being deleted regardless of age.

### The settings that control retention

These environment variables control what is saved and for how long:

    ```bash
    EXECUTIONS_DATA_SAVE_ON_SUCCESS=all
    EXECUTIONS_DATA_SAVE_ON_ERROR=all
    EXECUTIONS_DATA_SAVE_ON_PROGRESS=false
    EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=false
    EXECUTIONS_DATA_PRUNE=true
    EXECUTIONS_DATA_MAX_AGE=168
    EXECUTIONS_DATA_PRUNE_MAX_COUNT=50000
    ```

What each one does:

 * **`EXECUTIONS_DATA_SAVE_ON_SUCCESS`** — whether to save data for successful runs.
   Setting it to `none` saves the most space: the run is recorded as successful,
   but the data that passed through the nodes is not stored. The trade-off is that
   you cannot inspect a successful run afterwards, which matters when a customer
   asks why an invoice went out twice.
 * **`EXECUTIONS_DATA_SAVE_ON_ERROR`** — whether to save data for failed runs. Keep
   this at `all` in almost every setup; failed runs are the ones you need to debug.
 * **`EXECUTIONS_DATA_SAVE_ON_PROGRESS`** — whether to write to the database after
   every node, which allows resuming a failed run from the node where it stopped.
   Leave it off unless you rely on that resume behaviour; on a busy workflow the
   write traffic is significant.
 * **`EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS`** — whether to save runs you trigger
   by hand from the editor. Turning it off keeps test runs out of your history.
 * **`EXECUTIONS_DATA_PRUNE`** — enables automatic deletion of old executions. Without
   this, history grows without limit.
 * **`EXECUTIONS_DATA_MAX_AGE`** — how long to keep executions, in hours. `168` 
   is one week; `336` is two weeks.
 * **`EXECUTIONS_DATA_PRUNE_MAX_COUNT`** — the maximum number of executions to keep.
   Whichever limit bites first — age or count — is what deletes your history, so
   set both deliberately for your volume rather than assuming the age limit is the
   one in control.

A balanced starting point for a production instance is: save everything on error,
save success data for a short window (72 hours to one week), prune automatically,
and set the count cap to fit your database size. If you need longer audit history,
export execution data to external storage rather than keeping it all in the live
database.

### Retention is not a backup

Execution history is operational data, not a backup: pruning deletes it by design.
Back up workflows, credentials, the key, and the database separately — see [how to back up and restore n8n workflows and credentials](https://offshorehosting.pk/blog/back-up-restore-n8n-workflows/).

## Concurrency and timeouts

Two more settings prevent a busy instance from collapsing:

 * **Concurrency limit** (`N8N_CONCURRENCY_PRODUCTION_LIMIT`) caps how many production
   executions run at once. Without a cap, a burst of webhooks can exhaust memory.
   Start at the worker default of around 10 parallel executions per worker and adjust
   based on whether your workflows are CPU-heavy (lower) or mostly waiting on APIs(
   higher).
 * **Execution timeout** (`EXECUTIONS_TIMEOUT`) caps how long a single execution
   may run. Without one, a stuck workflow can consume memory indefinitely. Set a
   timeout that is generous for your slowest legitimate workflow and short enough
   to kill a genuinely stuck one.

## A checklist before you go to production

 1. Pin the public webhook URL and test a webhook from outside your network.
 2. Decide regular vs queue mode based on real concurrency, not guesswork.
 3. Use PostgreSQL for anything beyond light personal use.
 4. Set the retention variables explicitly — do not rely on defaults.
 5. Set a concurrency limit and an execution timeout.
 6. Pin the n8n image version (and digest) so main and workers can never drift apart.
 7. Back up the database and the encryption key, and test a restore.

## What this needs from the server

Queue mode means running Redis and PostgreSQL alongside n8n, plus one or more worker
processes. That is a small multi-service deployment, and it needs a server with 
enough memory, persistent volumes, and the freedom to run Docker containers and 
set environment variables. A [VPS hosting](https://offshorehosting.pk/vps-hosting/)
plan is the usual fit: you control the services, the versions, and the retention
settings, rather than inheriting someone else’s defaults. [TO BE CONFIRMED: whether
Offshore Hosting VPS plans include Redis/PostgreSQL support or managed n8n — confirm
before publishing any such claim.]

## Key takeaways

 * Webhooks need a correct public URL and a response strategy matched to the sender;
   design for duplicate deliveries.
 * Queue mode separates execution from the main process via Redis, so a crash does
   not lose queued work — but Redis itself becomes critical.
 * Execution history grows fast; set save, prune, age, and count limits deliberately,
   and remember the count cap can bite before the age limit.
 * Keep error data, be selective about success data, and export audit history elsewhere
   if you need it long-term.
 * Retention is not a backup. Back up workflows, credentials, the key, and the database
   separately.

## Sources

 * Dev.to, “Running n8n in Production: Queue Mode, Workers, and the Settings That
   Keep It Alive” — https://dev.to/bubblesstudio/running-n8n-in-production-queue-
   mode-workers-and-the-settings-that-keep-it-alive-3o9
 * Toolient, “n8n Environment Variables You Must Set (Production Checklist)” — https://
   www.toolient.com/2026/01/n8n-environment-variables-production-checklist.html
 * Lumadock, “Prune n8n Executions: EXECUTIONS_DATA_MAX_AGE and Friends” — https://
   lumadock.com/tutorials/n8n-prune-executions
 * Osher, “Guide to n8n Configuration Settings: Environment Variables, Database,
   Queues, and Production Tuning” — https://osher.com.au/blog/guide-to-n8n-configuration-
   settings/

## Sources

 * {‘title’: ‘Running n8n in Production: Queue Mode, Workers, and the Settings That
   Keep It Alive’, ‘url’: ‘https://dev.to/bubblesstudio/running-n8n-in-production-
   queue-mode-workers-and-the-settings-that-keep-it-alive-3o9’}
 * {‘title’: ‘n8n Environment Variables You Must Set (Production Checklist)’, ‘url’:‘
   https://www.toolient.com/2026/01/n8n-environment-variables-production-checklist.
   html’}
 * {‘title’: ‘Prune n8n Executions: EXECUTIONS_DATA_MAX_AGE and Friends’, ‘url’:‘
   https://lumadock.com/tutorials/n8n-prune-executions’}
 * {‘title’: ‘Guide to n8n Configuration Settings: Environment Variables, Database,
   Queues, and Production Tuning’, ‘url’: ‘https://osher.com.au/blog/guide-to-n8n-
   configuration-settings/’}
