Node.js6 min read

Rate Limiting in Node.js APIs

Protect your API from abuse with rate limiting. Implement request throttling and prevent DDoS attacks.

Sarah Chen
December 19, 2025
0.0k0

Rate Limiting in Node.js APIs

Rate limiting prevents abuse by limiting how many requests a client can make.

Setup

npm install express-rate-limit

Basic Rate Limiter

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

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 minutes
  max: 100,                   // 100 requests per window
  message: { error: 'Too many requests, please try again later' }
});

// Apply to all requests
app.use(limiter);

API-Specific Limits

// Strict limit for auth routes
const authLimiter = rateLimit({
  windowMs: 60 * 60 * 1000,  // 1 hour
  max: 5,                     // 5 attempts
  message: { error: 'Too many login attempts' }
});

app.use('/api/auth', authLimiter);

// Relaxed limit for general API
const apiLimiter = rateLimit({
  windowMs: 60 * 1000,  // 1 minute
  max: 60               // 60 requests per minute
});

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

Custom Key Generator

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  keyGenerator: (req) => {
    // Rate limit by user ID if authenticated, IP otherwise
    return req.user?.id || req.ip;
  }
});

Skip Certain Requests

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  skip: (req) => {
    // Don't rate limit admins
    return req.user?.role === 'admin';
  }
});

Custom Response Headers

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  standardHeaders: true,  // Return rate limit info in headers
  legacyHeaders: false    // Disable X-RateLimit headers
});

// Response headers:
// RateLimit-Limit: 100
// RateLimit-Remaining: 99
// RateLimit-Reset: 1234567890

Redis Store (for distributed apps)

npm install rate-limit-redis
const RedisStore = require('rate-limit-redis');
const redis = require('redis');

const client = redis.createClient();

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  store: new RedisStore({
    sendCommand: (...args) => client.sendCommand(args)
  })
});

Different Limits by Plan

const createLimiter = (max) => rateLimit({
  windowMs: 60 * 1000,
  max,
  keyGenerator: (req) => req.user?.id || req.ip
});

const limiters = {
  free: createLimiter(10),
  pro: createLimiter(100),
  enterprise: createLimiter(1000)
};

function dynamicRateLimit(req, res, next) {
  const plan = req.user?.plan || 'free';
  return limiters[plan](req, res, next);
}

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

Slow Down Instead of Block

npm install express-slow-down
const slowDown = require('express-slow-down');

const speedLimiter = slowDown({
  windowMs: 15 * 60 * 1000,
  delayAfter: 50,       // Allow 50 requests without delay
  delayMs: (hits) => hits * 100  // Add 100ms per request after 50
});

app.use(speedLimiter);

Complete Setup

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

// General API limit
app.use('/api', rateLimit({
  windowMs: 60 * 1000,
  max: 60,
  standardHeaders: true
}));

// Strict auth limit
app.use('/api/auth/login', rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: { error: 'Too many login attempts. Try again in 15 minutes.' }
}));

// Very strict for password reset
app.use('/api/auth/forgot-password', rateLimit({
  windowMs: 60 * 60 * 1000,
  max: 3
}));

Key Takeaway

Rate limiting is essential API security. Use express-rate-limit for quick setup. Apply stricter limits to sensitive endpoints (auth, payments). Use Redis store for distributed systems. Always return informative error messages.

#Node.js#Express#Rate Limiting#Security#Intermediate