Skip to content

How Many Requests Per Second Can a Single Node.js Process Handle?

Problem

When I planned to deploy my Node.js application, I wondered: how many requests per second can a single process actually handle? I needed concrete numbers for capacity planning.

Environment

  • Node.js 20.x
  • Express.js backend
  • PostgreSQL database
  • Running on Linux server

What happened?

I searched for benchmarks and found that most answers were too generic: “it depends.” So I dug into production experiences from real developers.

Here’s what I found from actual production systems:

ScenarioThroughputContext
Simple API endpoint10k+ concurrent usersSingle process, minimal logic
Moderate business logic~120 RPS100-120ms/request, 70% CPU
SSR with Next.jsLower 4 digitsSignificantly reduced vs API
SQS message processing100/secDB saves, 0.25vCPU, 512MB

The numbers vary wildly because throughput depends on what your code actually does.

How to estimate your throughput?

Factor #1: Type of Workload

Different workloads have very different capacities:

Workload TypeExpected RPSWhy
Static API proxy5,000-10,000+Minimal CPU, pure I/O
Database CRUD500-2,000Depends on DB latency
Business logic heavy100-500CPU-bound operations
SSR/Template rendering1,000-3,000Synchronous rendering
JSON-heavy processing200-800Synchronous parsing

Factor #2: Event Loop Health

Node.js handles requests on a single thread via the event loop. When the loop is blocked, all concurrent requests wait.

event-loop-block.js
// BAD: Blocks event loop (synchronous CPU work)
app.get('/process', (req, res) => {
const result = heavyCalculation(10000000) // Blocks!
res.json(result)
})
// GOOD: Offload to worker thread
app.get('/process', async (req, res) => {
const result = await runInWorkerThread(heavyCalculation, 10000000)
res.json(result)
})

Factor #3: JSON Parsing Impact

One insight I found crucial: JSON parsing is synchronous. Small JSON payloads (under 1KB) are fine, but larger payloads slow things down significantly.

JSON parsing overhead
Payload size | Parse time (approx)
------------|---------------------
< 1KB | Negligible
1-10KB | ~1-5ms
10-100KB | ~5-50ms
> 100KB | Can block event loop

When should I consider clustering?

Clustering becomes beneficial when:

  • CPU utilization consistently >70% on single process
  • Request latency increases under load despite available memory
  • Event loop lag exceeds 50-100ms
  • Business logic is CPU-intensive (image processing, cryptography)

But before adding clustering, I should optimize first.

Monitor Event Loop Lag

monitor-event-loop.js
const { monitorEventLoopDelay } = require('perf_hooks')
const h = monitorEventLoopDelay()
h.enable()
setInterval(() => {
console.log(`Event loop lag: min=${h.min}ms, mean=${h.mean}ms, max=${h.max}ms`)
}, 5000)

If I see lag exceeding 50ms consistently, that’s a signal to either optimize code or consider clustering.

Benchmark Your Actual Application

Synthetic benchmarks don’t reflect real performance. I should test my actual endpoints:

benchmark.js
const autocannon = require('autocannon')
async function benchmark() {
const result = await autocannon({
url: 'http://localhost:3000/api/your-endpoint',
connections: 100,
duration: 30
})
console.log(`Requests/sec: ${result.requests.mean}`)
console.log(`Latency: ${result.latency.mean}ms`)
console.log(`Errors: ${result.errors}`)
}
benchmark()

The reason

The key reason throughput varies so much is the event loop architecture:

  1. I/O-bound operations (database queries, API calls) don’t block the loop - high throughput
  2. CPU-bound operations (JSON parsing, encryption, templating) block the loop - low throughput
  3. SSR rendering involves synchronous template processing - reduced capacity

This is why “it depends” is actually the honest answer. A simple proxy server can handle 10,000+ connections, but a complex business app might struggle at 100 RPS.

Common Mistakes

MistakeImpactSolution
Premature clusteringComplexity without benefitBenchmark first
Blocking event loopAll requests hangUse worker threads
Ignoring JSON payload sizeUnexpected slowdownsStream large payloads
Not monitoring event loopSilent performance degradationAdd monitoring
Assuming linear scalingMisleading capacity plansTest with real traffic

Summary

In this post, I explored how many requests a single Node.js process can handle. The key point is: 10,000+ concurrent connections for simple APIs, or 100-500 RPS for typical business logic. Before adding clustering complexity, I should benchmark my actual workload, monitor event loop health, and optimize blocking operations first.

The real answer: test with realistic traffic patterns. Most applications don’t need clustering until they reach hundreds of requests per second with non-trivial processing.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments