Hard20 minExpress.js Fundamentals
UpdatedAug 5, 2026
Edit

Express Rate Limiting

Question Variations

  • "Why is an in-memory Express rate limiter incorrect with multiple replicas?"
  • "Should an API limit by IP address, user, or API key?"
  • "What should a client do after receiving 429?"

Why This Is Asked

Rate limiting is a common API protection with real trade-offs in key selection, distributed state, and client behavior. Interviewers want to see a design that limits abuse without creating an easy denial of service for legitimate users.

Key Concepts

  • A limit needs a scope, key, window or refill policy, and an explicit client response.
  • User or tenant identity is often safer than IP alone after authentication.
  • Distributed deployments need a shared atomic store or gateway-level enforcement.
  • Authentication endpoints need stricter limits and careful error responses.

Question Variations

  • “Why is an in-memory Express rate limiter incorrect with multiple replicas?”
  • “Should an API limit by IP address, user, or API key?”
  • “What should a client do after receiving 429?”

Answers by Technology

+ Add Variant
Express.jsImprove this answer ✏️

Expected Answer (Express 5.1.0 / Node.js 18+)

Rate limiting restricts requests over time to control abuse and protect capacity. Define the protected operation, the key—for example an API key, authenticated user, tenant, or IP—the policy, and the response. Authentication and password-reset endpoints usually require stricter limits than public reads. Return 429 with a useful retry indication, but do not disclose whether a specific account exists.

An in-memory counter works only for a single process and loses state on restart. In a horizontally scaled Express service, enforce at an API gateway or use a shared store that can increment and expire counters atomically. IP-only limits are weak behind NATs and proxies, so choose the identity available at that stage and layer protections. Rate limiting should complement input limits, authentication, and upstream capacity controls.

Why It Matters

Poor limits either fail open under scale or block many legitimate customers sharing an address. Well-designed limits protect reliability and credentials.

Code Example

import express, { NextFunction, Request, Response } from 'express';

const app = express();
const attempts = new Map<string, number>();
function demoLimit(req: Request, res: Response, next: NextFunction) {
  const key = req.ip ?? 'unknown';
  const count = (attempts.get(key) ?? 0) + 1;
  attempts.set(key, count);
  if (count > 5) return res.status(429).set('Retry-After', '60').json({ error: 'try again later' });
  return next();
}
app.post('/login', demoLimit, (_req: Request, res: Response) => res.sendStatus(204));
app.listen(3000);

Common Mistakes

  • Deploying a process-local counter as a distributed limiter: Each replica grants its own full quota.
  • Trusting req.ip without proxy configuration: A spoofed or proxy IP can make the limit ineffective or unfair.

Follow-up Questions

  • Which algorithm handles bursts better than a fixed window? (Answer: Token bucket permits controlled bursts while maintaining an average rate.)
  • Why limit authenticated users as well as IPs? (Answer: One user can distribute abuse across many addresses.)