Rate Limiting — Protect Your Node.js API

Sanjeev SharmaSanjeev Sharma
2 min read

Advertisement

Rate limiting prevents abuse and DDoS attacks. Essential for production APIs.

express-rate-limit

npm install express-rate-limit
import rateLimit from "express-rate-limit";

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per windowMs
  message: "Too many requests",
  standardHeaders: true, // Return rate limit info in headers
  legacyHeaders: false,
});

app.use(limiter);

// Stricter limit for login
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  skipSuccessfulRequests: true, // Don't count successful logins
});

app.post("/login", loginLimiter, (req, res) => {
  // Handle login
});

Redis-based Rate Limiting

import RedisStore from "rate-limit-redis";
import { createClient } from "redis";

const redisClient = createClient();

const limiter = rateLimit({
  store: new RedisStore({
    client: redisClient,
    prefix: "rl:", // Key prefix
  }),
  windowMs: 60 * 1000, // 1 minute
  max: 30,
});

app.use(limiter);

Custom Rate Limit

async function checkRateLimit(
  key: string,
  limit = 100,
  window = 3600
): Promise<boolean> {
  const current = await redis.incr(key);
  if (current === 1) {
    await redis.expire(key, window);
  }
  return current <= limit;
}

app.use(async (req, res, next) => {
  const allowed = await checkRateLimit(`ip:${req.ip}`);
  if (!allowed) {
    return res.status(429).json({ error: "Too many requests" });
  }
  next();
});

User-level Rate Limiting

app.post("/api/data", async (req: any, res) => {
  if (!req.user) return res.status(401).json({ error: "Not auth" });

  const allowed = await checkRateLimit(
    `user:${req.user.id}:api`,
    1000, // 1000 requests per hour
    3600
  );

  if (!allowed) {
    return res.status(429).json({ error: "API quota exceeded" });
  }

  // Process request
});

FAQ

Q: Should rate limiting be on server or reverse proxy? A: Both. Proxy catches obvious abuse, server handles legitimate users.

Q: How do I handle bursts? A: Use sliding window or token bucket algorithms.

Q: What about different plans? A: Store plan info with user, apply different limits per plan.


Rate limiting is non-negotiable for production APIs. Implement it from day one.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro