What is Rate Limiting?

Download this article as a PDF on the Codeflare Mobile App

Rate limiting restricts the number of requests a client can make within a specific time window.

Example:

  • Max: 100 requests per 15 minutes per IP
  • If exceeded → request is blocked (usually with 429 Too Many Requests)

Why it matters:

  • Prevents brute-force attacks
  • Stops API abuse
  • Protects server resources
  • Ensures fair usage across users

What is Throttling?

Throttling controls the rate at which requests are processed, often by slowing them down rather than blocking them outright.

Learn on the Go. Download the Codeflare Mobile App from Google Play Store

Example:

  • Allow 1 request per second
  • Extra requests are delayed or queued

Key difference:

FeatureRate LimitingThrottling
BehaviorBlocks excess requestsSlows them down
Response429 errorDelayed response
Use caseSecurity & abuse controlTraffic shaping & smoothing

Core Algorithms Behind Rate Limiting

Understanding these helps you design custom systems.

1. Fixed Window Counter

  • Count requests in a fixed time window (e.g., per minute)
  • Simple but can cause bursts

👉 Problem: A user can send many requests at the boundary

2. Sliding Window Log

  • Stores timestamps of requests
  • More accurate but memory-heavy

3. Sliding Window Counter

  • Hybrid approach (more efficient than logs)

4. Token Bucket (Best for Throttling)

  • Tokens are added at a steady rate
  • Requests consume tokens
  • If no tokens → wait or reject

5. Leaky Bucket

  • Requests are processed at a fixed rate
  • Excess requests are queued or dropped

Implementing Rate Limiting in Node.js

1. Using express-rate-limit (Most Common)

Install:

npm install express-rate-limit

Basic Setup:

const express = require('express');
const rateLimit = require('express-rate-limit');

const app = express();

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP
  message: 'Too many requests, try again later',
  standardHeaders: true,
  legacyHeaders: false,
});

app.use('/api', limiter);

app.get('/api/data', (req, res) => {
  res.send('API response');
});

app.listen(3000);

2. Advanced Rate Limiting with Redis (Production Ready)

For distributed systems (multiple servers), in-memory limits won’t work.

Use Redis.

Install:

npm install rate-limiter-flexible ioredis

Example:

const { RateLimiterRedis } = require('rate-limiter-flexible');
const Redis = require('ioredis');

const redisClient = new Redis();

const rateLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 10, // 10 requests
  duration: 1, // per second
});

const express = require('express');
const app = express();

app.use(async (req, res, next) => {
  try {
    await rateLimiter.consume(req.ip);
    next();
  } catch {
    res.status(429).send('Too Many Requests');
  }
});

3. Implementing Throttling (Custom Logic)

Simple Delay Throttling:

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

app.use(async (req, res, next) => {
  await delay(500); // delay each request
  next();
});

4. Token Bucket Example

class TokenBucket {
  constructor(capacity, refillRate) {
    this.capacity = capacity;
    this.tokens = capacity;
    this.refillRate = refillRate;
    this.lastRefill = Date.now();
  }

  refill() {
    const now = Date.now();
    const diff = (now - this.lastRefill) / 1000;
    this.tokens = Math.min(this.capacity, this.tokens + diff * this.refillRate);
    this.lastRefill = now;
  }

  consume() {
    this.refill();
    if (this.tokens >= 1) {
      this.tokens -= 1;
      return true;
    }
    return false;
  }
}

Best Practices for Node.js Apps

1. Use IP + User-Based Limiting

  • Combine IP + API key / user ID
  • Prevent shared IP abuse

2. Different Limits per Route

app.use('/login', strictLimiter);
app.use('/api', generalLimiter);

3. Protect Sensitive Endpoints

  • Login
  • Password reset
  • Payment APIs

4. Use Headers for Transparency

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 20

5. Graceful Handling

Return helpful errors:

{
  "error": "Too many requests",
  "retry_after": "60 seconds"
}

6. Combine with Other Security Layers

  • CAPTCHA
  • API keys
  • Authentication (JWT)
  • WAF (Cloudflare in for apps like Codeflare)

Real-World Use Cases

1. Login Protection

  • 5 attempts per minute
  • Prevent brute-force attacks

2. Public APIs

  • Free tier: 100 requests/hour
  • Paid tier: 1000 requests/hour

3. Payment Systems

  • Strict throttling to prevent fraud spikes

4. Scraping Prevention

  • Detect unusual request bursts

⚠️ Common Pitfalls

  • ❌ Using in-memory limiter in distributed apps
  • ❌ Not handling proxies (X-Forwarded-For)
  • ❌ Blocking legitimate users (too strict limits)
  • ❌ Ignoring burst traffic patterns

Conclusion

  • Rate limiting = control how many requests are allowed
  • Throttling = control how fast requests are processed
  • Both are critical for:
    • Security
    • Performance
    • Scalability

Recent Posts

How To Migrate from PostgreSQL to MySQL

Database migration is one of the most challenging tasks in software engineering. While both PostgreSQL…

2 days ago

Hidden Gems Inside Modern JavaScript

Modern JavaScript isn’t just let, const, arrow functions, and promises anymore. Over the years, the language has…

3 days ago

Software Developer Pain Points Ranked: What Frustrates Developers the Most?

Software development is one of the most rewarding careers in technology, but it is also…

3 days ago

How to Print Documents in JavaScript

Printing a document in JavaScript usually means triggering the browser’s print dialog and controlling what…

5 days ago

CSS Display Cheatsheet

The display property controls how an element behaves in the layout and how its children are arranged. Access software…

1 week ago

10 JavaScript Habits Destroying Your Code

JavaScript is one of the most flexible programming languages ever created. That flexibility is powerful,…

1 week ago