← Back to list

Designing Scalable APIs: From 100 to 1 Million Requests

When an API is first built, it usually works well with a small number of users. Requests are fast, responses are clean, and everything…

Pawan Sisodiya · 2026-03-23 13:30 · 0 claps · 2.8 min read
#rest-api #scalable-apis #nodejs-event-loop #api-performance-improve
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Designing Scalable APIs: From 100 to 1 Million Requests

When an API is first built, it usually works well with a small number of users. Requests are fast, responses are clean, and everything feels stable.

However, as usage grows, the same API often starts slowing down. Response times increase, CPU usage spikes, and in some cases, the system becomes unresponsive.

Scaling an API is not just about adding more servers. It is about designing the system in a way that can handle increasing load efficiently.

This article focuses on practical concepts that help APIs scale from handling a few hundred requests to millions.

Understanding Where Things Break

Before scaling, it is important to understand why systems fail under load.

Some common bottlenecks include:

  • CPU-heavy operations
  • Slow database queries
  • Too many concurrent requests
  • Blocking operations in the application

In many Node.js applications, one of the biggest issues is not infrastructure — it is how the code interacts with the event loop.

The Event Loop: More Practical Than Theoretical

Most developers have heard that Node.js is “single-threaded” and uses an event loop. However, this knowledge is often limited to interview preparation.

In real applications, the event loop is the core reason why an API either scales well or fails under pressure.

The event loop is responsible for handling all incoming requests. If it gets blocked, the entire application becomes slow.

What Blocks the Event Loop?

  • Heavy computations (large loops, data processing)
  • Synchronous file operations
  • Long-running tasks executed directly in request handlers

A simple example:

// Bad: blocks event loop
app.get('/process', (req, res) => {
  let sum = 0;
  for (let i = 0; i < 1e9; i++) {
    sum += i;
  }
  res.send("Done");
});

While this loop runs, no other request can be processed.

The Rule

A scalable Node.js API follows one simple rule:

Never block the event loop.

Using All CPU Cores (Node.js Limitation)

By default, Node.js runs on a single CPU core. Even if a machine has multiple cores, only one is used.

This becomes a major limitation under high load.

Solution: Cluster / Fork

Node.js provides a way to create multiple instances of the same server using the cluster module.

Each instance runs on a different CPU core.

const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
  const numCPUs = os.cpus().length;
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  // start server
}

This allows the application to handle more requests in parallel.

Worker Threads vs Child Processes

Many developers are aware of these terms but are unsure when to use them.

Worker Threads

  • Used for CPU-heavy tasks
  • Runs in the same process but different thread
  • Shares memory

Best for:

  • Image processing
  • Data transformations
  • Complex calculations

Child Processes

  • Runs a separate process
  • Completely isolated
  • Useful for running external scripts or services

Best for:

  • Running shell commands
  • Executing separate services

When Not to Use Them

If the task is already asynchronous (like database calls or API requests), there is usually no need for worker threads or child processes.

Horizontal Scaling

Scaling is not limited to a single machine.

To handle large traffic:

  • Run multiple instances of the API
  • Use a load balancer (NGINX, cloud load balancer)
  • Keep APIs stateless

Stateless design ensures any request can be handled by any server.

Caching: Reducing Unnecessary Work

One of the easiest ways to scale is to avoid doing the same work repeatedly.

Caching helps reduce:

  • Database load
  • Response time

Common approaches:

  • In-memory cache
  • Redis
  • CDN (for static content)

Database Optimization

Even a well-designed API can fail if the database is slow.

Important practices:

  • Use indexes properly
  • Avoid unnecessary queries
  • Use pagination instead of loading large datasets
  • Use connection pooling

Rate Limiting

If too many requests hit the API at once, even a good system can crash.

Rate limiting helps:

  • Prevent abuse
  • Protect resources
  • Maintain stability

Monitoring and Observability

Scaling without visibility is risky.

It is important to track:

  • Response times
  • Error rates
  • CPU and memory usage

Tools like logging systems and monitoring platforms help identify issues before they become critical.

Final Thoughts

Scaling an API is not achieved through a single change. It is the result of multiple small decisions:

  • Writing non-blocking code
  • Using system resources efficiently
  • Distributing load properly
  • Monitoring performance continuously

Many performance issues are not caused by infrastructure limitations, but by how the application is written.

Understanding concepts like the event loop, worker threads, and process management in a practical way makes a significant difference when building scalable systems.


메타데이터
post_id
adf6ef12f617
slug
designing-scalable-apis-from-100-to-1-million-requests-adf6ef12f617
url
https://medium.com/@sisodiya.pawan85/designing-scalable-apis-from-100-to-1-million-requests-adf6ef12f617
canonical_url
https://medium.com/@sisodiya.pawan85/designing-scalable-apis-from-100-to-1-million-requests-adf6ef12f617
author_url
https://medium.com/@sisodiya.pawan85
status
ok
fetched_at
2026-08-27 07:37:15