mcpField
R
rate-limiting

rate-limiting

github.com/claude-dev-suiteDevelopment4640 installsUpdated 2d ago
Repository

About rate-limiting

A rate-limiting reference for developers, with Express and Spring Boot examples, Redis sliding windows, and algorithm comparisons to guide strategy and response-header configuration.

Key features

  1. 01Express rate-limiting example
  2. 02Redis sliding-window implementation
  3. 03Rate-limiting algorithm comparison
  4. 04Spring Boot and Bucket4j example
  5. 05Response headers and production checklist

Use cases

  1. 01Add request limits to an API
  2. 02Use Redis limiting across servers
  3. 03Compare rate-limiting algorithms
  4. 04Configure 429 responses and retry hints

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill rate-limiting

After installing, type/rate-limitingin Claude Code to confirm it loaded.

Details

From the project README

Rate Limiting

Express (express-rate-limit)

import rateLimit from 'express-rate-limit';
import RedisStore from 'rate-limit-redis';
import { createClient } from 'redis';

const redis = createClient({ url: process.env.REDIS_URL });

// Global rate limit
const globalLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  limit: 100,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
  store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
  message: { error: 'Too many requests, try again later' },
});

app.use(globalLimiter);

// Stricter limit on auth endpoints
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  limit: 5,
  keyGenerator: (req) => req.body.email || req.ip, // By email, not just IP
  store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
});

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

Redis Sliding Window (custom)

async function isRateLimited(key: string, limit: number, windowSec: number): Promise<boolean> {
  const now = Date.now();
  const windowStart = now - windowSec * 1000;

  const multi = redis.multi();
  multi.zRemRangeByScore(key, 0, windowStart);    // Remove old entries
  multi.zAdd(key, { score: now, value: `${now}` });
  multi.zCard(key);                                  // Count in window
  multi.expire(key, windowSec);

  const results = await multi.exec();
  const count = results![2] as number;
  return count > limit;
}

// Usage
if (await isRateLimited(`rl:${userId}`, 100, 60)) {
  return res.status(429).json({ error: 'Rate limit exceeded' });
}

Algorithm Comparison

AlgorithmPrecisionMemoryBest For
Fixed windowLow (burst at edges)Very lowSimple APIs
Sliding window logHighMediumAccurate limiting
Sliding window counterMediumLowBalance of accuracy & memory
Token bucketMediumLowBurst-friendly APIs

Spring Boot (Bucket4j)

@Bean
public FilterRegistrationBean<RateLimitFilter> rateLimitFilter() {
    var filter = new RateLimitFilter(
        Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(1)))
    );
    var registration = new FilterRegistrationBean<>(filter);
    registration.addUrlPatterns("/api/*");
    return registration;
}

Response Headers

// Standard rate limit headers (RFC draft-7)
res.set({
  'RateLimit-Limit': '100',
  'RateLimit-Remaining': `${remaining}`,
  'RateLimit-Reset': `${resetTimestamp}`,
  'Retry-After': `${retryAfterSeconds}`, // On 429 responses
});

Anti-Patterns

Anti-PatternFix
In-memory rate limiting in multi-serverUse Redis-backed store
Rate limit by IP onlyAlso limit by user ID or API key
No rate limit headers in responseSend RateLimit-* headers for client awareness
Same limit for all endpointsTighter limits on auth, webhooks, expensive ops
No Retry-After on 429Include Retry-After header

Production Checklist

  • Redis-backed rate limiting for distributed deployments
  • Per-endpoint rate limit configuration
  • Standard rate limit headers in responses
  • Retry-After header on 429 responses
  • Rate limit by user ID (not just IP)
  • Monitoring: rate limit hit frequency

Comments

Markdown supported