n8n webhook performance on a small VPS is better than most people expect and flatter than the core count suggests. With n8n 2.46.6 in regular mode, a Webhook → Code node → response workflow peaked at 15.04 executions per second on a 2 vCPU Hetzner CX23, 31.93 on the 4 vCPU CX33 and 36.14 on the 8 vCPU CX43. No server failed a single request, even at 50 concurrent.

Why this matters now: n8n 2.x runs Code nodes through task runners by default, and the n8n docs publish benchmark charts but no per-server executions/s or latency. If you are sizing a VPS for webhooks, these are the numbers you need. This report is part of our n8n hosting section.

Tested in the Lab Hetzner CX23, CX33, CX43, CAX11, CAX21 · n8n 2.46.6 · Nov 2026

What we tested

Five Hetzner Cloud servers in Helsinki, all Ubuntu 24.04, tested on 5 November 2026:

  • CX23: 2 vCPU Intel Xeon (Skylake), 4 GB RAM, 6.64 € a month
  • CAX11: 2 vCPU ARM (Neoverse-N1), 4 GB, 7.25 €
  • CX33: 4 vCPU AMD EPYC-Rome, 8 GB, 10.27 €
  • CAX21: 4 vCPU ARM, 8 GB, 12.69 €
  • CX43: 8 vCPU AMD EPYC-Rome, 16 GB, 19.35 €

A vCPU is a virtual CPU core; on these shared plans it is a slice of a physical core that other customers also use. Prices are gross per month from the Hetzner Cloud API, checked 5 November 2026.

The stack

The same Docker Compose stack we run in production: docker.n8n.io/n8nio/n8n:2.46.6 plus postgres:16, with N8N_RUNNERS_ENABLED, EXECUTIONS_DATA_PRUNE and diagnostics off. Execution mode is the default regular mode (no Redis, no workers). We did not configure an external runner, so the Code node ran in a task runner launched by n8n itself as a child process, which the n8n docs call internal mode.

The workflow

One webhook (POST, response from the last node) and one Code node that doubles a number from the request body and adds a timestamp. Every execution is saved to PostgreSQL (saveDataSuccessExecution: all), so each request means one HTTP request, one task runner call and database writes. This is a light workflow. Anything that calls an external API, or processes large items, will be slower.

The load

ApacheBench (ab) sent a small JSON body to http://127.0.0.1:5678/webhook/lab-bench after a 200-request warm-up:

Concurrent requestsTotal requests
1300
10400
251000
502000

"Concurrent" means how many requests are open at the same time. "Executions/s" is completed requests per second as reported by ab; each request is one workflow execution. Median (p50) is the latency half the requests beat; p95 is the latency 95% of requests beat. n8n RAM was sampled with docker stats in a loop during each run.

The load came from the same server, over localhost. That removes network, TLS and reverse proxy time from the numbers, and it means ab and the RAM sampler used some of the same CPU as n8n. Read the results as the ceiling of the n8n stack itself, not as end-to-end latency for a caller on the internet. The test ran after our system benchmark: Supabase had been removed and Ollama was installed but had no model loaded.

Results

ServerConcurrent requestsExecutions/sMedianp95Failedn8n peak RAM
Hetzner CX232 vCPU · 4 GB · x86_64110.1104 ms162 ms0520 MiB
Hetzner CX232 vCPU · 4 GB · x86_641014.8697 ms893 ms0660 MiB
Hetzner CX232 vCPU · 4 GB · x86_642515.01,651 ms1,936 ms0825 MiB
Hetzner CX232 vCPU · 4 GB · x86_645014.23,445 ms3,954 ms01,003 MiB
Hetzner CX334 vCPU · 8 GB · x86_64113.572 ms133 ms0543 MiB
Hetzner CX334 vCPU · 8 GB · x86_641031.9311 ms438 ms0574 MiB
Hetzner CX334 vCPU · 8 GB · x86_642529.5841 ms986 ms0803 MiB
Hetzner CX334 vCPU · 8 GB · x86_645030.11,647 ms1,846 ms01,050 MiB
Hetzner CX438 vCPU · 15 GB · x86_64114.678 ms123 ms0546 MiB
Hetzner CX438 vCPU · 15 GB · x86_641036.1280 ms341 ms0544 MiB
Hetzner CX438 vCPU · 15 GB · x86_642535.0714 ms800 ms0694 MiB
Hetzner CX438 vCPU · 15 GB · x86_645032.41,539 ms1,682 ms01,016 MiB
Hetzner CAX112 vCPU · 4 GB · aarch64110.3113 ms156 ms0585 MiB
Hetzner CAX112 vCPU · 4 GB · aarch641013.9755 ms934 ms0640 MiB
Hetzner CAX112 vCPU · 4 GB · aarch642512.91,909 ms2,279 ms0729 MiB
Hetzner CAX112 vCPU · 4 GB · aarch645013.23,786 ms4,114 ms01,038 MiB
Hetzner CAX214 vCPU · 8 GB · aarch64112.0107 ms128 ms0539 MiB
Hetzner CAX214 vCPU · 8 GB · aarch641025.4402 ms528 ms0579 MiB
Hetzner CAX214 vCPU · 8 GB · aarch642525.8965 ms1,106 ms0824 MiB
Hetzner CAX214 vCPU · 8 GB · aarch645024.52,019 ms2,197 ms0859 MiB

Measured by AI Hosting Lab on 2026-11-05 · 5 servers · method · raw data

Peak throughput per server

ServervCPUBest executions/sAt 50 concurrentp95 at 50 concurrentFailed (all runs)
CX23215.0414.253954 ms0
CAX11213.913.24114 ms0
CAX21425.7724.512197 ms0
CX33431.9330.121846 ms0
CX43836.1432.361682 ms0

Four things the data shows

1. Throughput doubles from 2 to 4 vCPU, then flattens

From the CX23 to the CX33 the best result went from 15.04 to 31.93 executions/s, 2.16 times. From the CX33 to the CX43, doubling the cores again, it went to 36.14, only 1.13 times. On ARM the same step from 2 to 4 vCPU (CAX11 to CAX21) took it from 13.9 to 25.77. Every server was within 2% of its best result by 10 concurrent requests; more concurrency added no throughput.

2. Nothing failed; requests queued instead

All 3700 requests per server came back with 0 failed. When n8n is saturated, extra requests wait. You can see it in latency: on the CX23 the median went from 104 ms at 1 concurrent to 697 ms at 10, 1651 ms at 25 and 3445 ms at 50, while throughput stayed near 15. Divide concurrency by throughput and you get roughly that median: 50 open requests at 14.25 per second is about 3.5 seconds each. That is plain queueing. For webhook callers with a timeout (many SaaS senders retry after a few seconds) the p95 is the number to watch, not the failure count.

3. Single-request latency is mostly fixed overhead

At 1 concurrent request every server needed between 72 ms (CX33) and 113 ms (CAX11) per execution. The CX43 has twice the single-thread sysbench score of the CX33 (3470.38 vs 1620.94 events/s) and was not faster at 1 concurrent (78 ms vs 72 ms median). A lone execution spends its time in n8n's own work per request: routing the webhook, handing the code to the runner, writing the execution to PostgreSQL. A faster core barely shortens that.

4. The CPU benchmark does not predict n8n speed

CX231,823.0CX336,453.1CX4326,697.4CAX116,549.8CAX2113,210.5
cpu nt events s: · x86 ARM

The ARM CAX11 scored 6549.84 events/s in sysbench on all threads, almost the same as the CX33's 6453.15. In n8n the CX33 did 31.93 executions/s and the CAX11 13.9. The CX43 scored 26697.44, about four times the CX33, and gained 4.21 executions/s. For n8n in regular mode, the number of cores up to about four mattered more than how fast each core benchmarks. The ARM side is covered in n8n on an ARM server.

What limits throughput

The n8n queue mode docs describe the default setup: one main instance receives triggers and webhooks, and in regular mode it also runs the executions. That process is Node.js, and the Node.js docs state that it "runs JavaScript code in the Event Loop", one event loop per process, with a small worker pool for some I/O. So the main n8n process can only use a limited share of a large server.

Our reading of the numbers: on 2 vCPU, the n8n main process, the task runner, PostgreSQL and the load generator all compete for two cores, so throughput is capped near 15. At 4 vCPU each gets room and throughput doubles. Past that, the single main process is the bottleneck, so the CX43's extra cores probably go unused for this workload. We did not record CPU per process, so treat this as an explanation that fits the data, not a measured breakdown.

How n8n says to scale past one process

The documented path is queue mode: set EXECUTIONS_MODE=queue, add Redis as the message broker, and run worker processes that pick executions from the queue and write results to the database. n8n says a distributed setup on SQLite isn't supported, so you need PostgreSQL. For webhook-heavy loads the docs add webhook processors, separate n8n processes behind a load balancer that take incoming webhook requests, and say "This method allows n8n to process a huge number of parallel requests." Workers default to a concurrency of 10.

We have not tested queue mode yet. It is the next n8n test on our list, on the same servers, so you can see whether a CX43 with workers gets past the 36.14 executions/s we measured in regular mode.

Concurrency control in regular mode

The n8n docs say that in regular mode n8n doesn't limit how many production executions run at once, and that concurrency control is disabled by default. Setting N8N_CONCURRENCY_PRODUCTION_LIMIT makes extra executions wait in a first-in, first-out queue. That will not raise throughput, but it can stop a burst of heavy executions from exhausting RAM. We ran with the default.

RAM under load

The n8n container used 402.7 to 416.6 MiB idle and peaked between 859.3 MiB (CAX21) and 1049.6 MiB (CX33) during the 50-concurrent run. PostgreSQL used 57.78 to 64.64 MiB idle. MiB is mebibytes (1 MiB = 1.048576 MB). Even the 4 GB servers had room to spare. Full sizing advice is in n8n server requirements.

What it means for your workflows

  • Typical automations (a few hundred to a few thousand webhook calls a day) never come near 15 executions/s. A 2 vCPU server is plenty.
  • Bursty webhooks (a form, a store, a chat bot) care about p95 during the burst. At 10 concurrent the CX33 kept p95 at 438 ms, the CX23 at 893 ms.
  • Sustained high volume above about 30 executions/s of a light workflow is past what one regular-mode instance did on any server we tested. Plan for queue mode rather than a bigger server.

The n8n benchmark page states that n8n "can handle up to 220 workflow executions per second on a single instance", but gives no hardware or workflow for that figure, and its charts show the share of requests answered within 100 seconds. Our figures are lower and come with the server, the workflow and the script, so you can compare them with your own.

Run the test yourself

Our script is lab/n8n_load.sh. It writes a .env with random secrets, starts the n8n 2.46.6 + Postgres 16 compose, creates an owner and an API key through the REST API, imports and activates the workflow, warms up, then runs ab. It expects Docker, ab (package apache2-utils), curl and python3, all of which our bench.sh installs first. Run it as root on a throwaway server, never on your production n8n:

apt-get -y install docker.io docker-compose-v2 apache2-utils
bash n8n_load.sh
cat /root/n8nload.txt

The core of the test loop:

for c in 1 10 25 50; do
  n=$(( c<10 ? 300 : c*40 ))
  ab -q -n $n -c $c -p /tmp/body.json -T application/json http://127.0.0.1:5678/webhook/lab-bench > /tmp/ab_$c.txt 2>&1
done

To test your real workflow, replace the Code node with your own nodes and keep everything else. To include network and TLS, run ab from a second server against your public HTTPS URL. The full method for all our tests is on how we test.

Limits of this test

  • One run per server, on shared vCPU plans; a busy neighbour on another day could move results. CPU steal measured 0.0 % on all five during the system benchmark.
  • One light workflow. We have not measured workflows with HTTP Request nodes, AI nodes or large payloads yet.
  • Regular mode only, SQLite not tested, n8n 2.46.6 only.
  • Other providers are not yet tested in our Lab; testing is scheduled.

Next step: turn these numbers into a server choice with our best VPS for n8n verdict by use case.

Hetzner prices on this page include 21% VAT, as charged to our Czech (EU consumer) account by the Hetzner API on 2026-11-05. Without VAT (businesses, most buyers outside the EU): CX23 5.49 €, CX33 8.49 €, CX43 15.99 €, CAX11 5.99 €, CAX21 10.49 € per month.

FAQ

How many webhook requests per second can n8n handle?

On our tests with a Webhook to Code node workflow, n8n 2.46.6 in regular mode peaked at 15.04 executions/s on the 2 vCPU Hetzner CX23, 31.93 on the 4 vCPU CX33 and 36.14 on the 8 vCPU CX43. Heavier workflows will be slower. n8n's own docs quote up to 220 executions/s on a single instance, with no hardware given.

Does n8n drop webhook requests under load?

Not in our tests. All five servers answered every request, including 2000 requests at 50 concurrent, with 0 failed. Under overload the requests waited in line instead: p95 latency on the CX23 rose to 3954 ms.

Why does n8n not get faster with more CPU cores?

In regular mode one n8n main process receives the webhooks and runs the executions, and Node.js runs JavaScript on one event loop. Extra cores help the database and the Code node runner, but past 4 vCPU our throughput barely moved. The documented way to scale further is queue mode with workers and webhook processors.

How much RAM does n8n use under webhook load?

The n8n container idled at 402.7 to 416.6 MiB and peaked between 859.3 and 1049.6 MiB at 50 concurrent requests, depending on the server. PostgreSQL idled at about 58 to 65 MiB.

Sources

  1. n8n Docs, Performance and benchmarking (2026)
  2. n8n Docs, Queue mode (2026)
  3. n8n Docs, Concurrency control (2026)
  4. n8n Docs, Task runners (2026)
  5. Node.js, Don't block the event loop (2026)
  6. n8n Community, Self-hosted performance check (2024)