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 requests | Total requests |
|---|---|
| 1 | 300 |
| 10 | 400 |
| 25 | 1000 |
| 50 | 2000 |
"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.
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
| Server | Concurrent requests | Executions/s | Median | p95 | Failed | n8n peak RAM |
|---|---|---|---|---|---|---|
| Hetzner CX232 vCPU · 4 GB · x86_64 | 1 | 10.1 | 104 ms | 162 ms | 0 | 520 MiB |
| Hetzner CX232 vCPU · 4 GB · x86_64 | 10 | 14.8 | 697 ms | 893 ms | 0 | 660 MiB |
| Hetzner CX232 vCPU · 4 GB · x86_64 | 25 | 15.0 | 1,651 ms | 1,936 ms | 0 | 825 MiB |
| Hetzner CX232 vCPU · 4 GB · x86_64 | 50 | 14.2 | 3,445 ms | 3,954 ms | 0 | 1,003 MiB |
| Hetzner CX334 vCPU · 8 GB · x86_64 | 1 | 13.5 | 72 ms | 133 ms | 0 | 543 MiB |
| Hetzner CX334 vCPU · 8 GB · x86_64 | 10 | 31.9 | 311 ms | 438 ms | 0 | 574 MiB |
| Hetzner CX334 vCPU · 8 GB · x86_64 | 25 | 29.5 | 841 ms | 986 ms | 0 | 803 MiB |
| Hetzner CX334 vCPU · 8 GB · x86_64 | 50 | 30.1 | 1,647 ms | 1,846 ms | 0 | 1,050 MiB |
| Hetzner CX438 vCPU · 15 GB · x86_64 | 1 | 14.6 | 78 ms | 123 ms | 0 | 546 MiB |
| Hetzner CX438 vCPU · 15 GB · x86_64 | 10 | 36.1 | 280 ms | 341 ms | 0 | 544 MiB |
| Hetzner CX438 vCPU · 15 GB · x86_64 | 25 | 35.0 | 714 ms | 800 ms | 0 | 694 MiB |
| Hetzner CX438 vCPU · 15 GB · x86_64 | 50 | 32.4 | 1,539 ms | 1,682 ms | 0 | 1,016 MiB |
| Hetzner CAX112 vCPU · 4 GB · aarch64 | 1 | 10.3 | 113 ms | 156 ms | 0 | 585 MiB |
| Hetzner CAX112 vCPU · 4 GB · aarch64 | 10 | 13.9 | 755 ms | 934 ms | 0 | 640 MiB |
| Hetzner CAX112 vCPU · 4 GB · aarch64 | 25 | 12.9 | 1,909 ms | 2,279 ms | 0 | 729 MiB |
| Hetzner CAX112 vCPU · 4 GB · aarch64 | 50 | 13.2 | 3,786 ms | 4,114 ms | 0 | 1,038 MiB |
| Hetzner CAX214 vCPU · 8 GB · aarch64 | 1 | 12.0 | 107 ms | 128 ms | 0 | 539 MiB |
| Hetzner CAX214 vCPU · 8 GB · aarch64 | 10 | 25.4 | 402 ms | 528 ms | 0 | 579 MiB |
| Hetzner CAX214 vCPU · 8 GB · aarch64 | 25 | 25.8 | 965 ms | 1,106 ms | 0 | 824 MiB |
| Hetzner CAX214 vCPU · 8 GB · aarch64 | 50 | 24.5 | 2,019 ms | 2,197 ms | 0 | 859 MiB |
Measured by AI Hosting Lab on 2026-11-05 · 5 servers · method · raw data
Peak throughput per server
| Server | vCPU | Best executions/s | At 50 concurrent | p95 at 50 concurrent | Failed (all runs) |
|---|---|---|---|---|---|
| CX23 | 2 | 15.04 | 14.25 | 3954 ms | 0 |
| CAX11 | 2 | 13.9 | 13.2 | 4114 ms | 0 |
| CAX21 | 4 | 25.77 | 24.51 | 2197 ms | 0 |
| CX33 | 4 | 31.93 | 30.12 | 1846 ms | 0 |
| CX43 | 8 | 36.14 | 32.36 | 1682 ms | 0 |
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
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.



