javascript 56 lines · 7 steps

How token-bucket rate limiting works in Express

A per-user token bucket refills over time and rejects requests once a user runs out of tokens.

Explained by highlit
1class TokenBucket {
2 constructor({ capacity, refillPerSecond }) {
3 this.capacity = capacity;
4 this.refillPerSecond = refillPerSecond;
5 this.tokens = capacity;
6 this.lastRefill = Date.now();
7 }
8 
9 refill() {
10 const now = Date.now();
11 const elapsedSeconds = (now - this.lastRefill) / 1000;
12 if (elapsedSeconds <= 0) return;
13 this.tokens = Math.min(this.capacity, this.tokens + elapsedSeconds * this.refillPerSecond);
14 this.lastRefill = now;
15 }
16 
17 tryConsume(cost = 1) {
18 this.refill();
19 if (this.tokens >= cost) {
20 this.tokens -= cost;
21 return true;
22 }
23 return false;
24 }
25}
26 
27class RateLimiter {
28 constructor(options) {
29 this.options = options;
30 this.buckets = new Map();
31 }
32 
33 bucketFor(userId) {
34 let bucket = this.buckets.get(userId);
35 if (!bucket) {
36 bucket = new TokenBucket(this.options);
37 this.buckets.set(userId, bucket);
38 }
39 return bucket;
40 }
41 
42 allow(userId, cost = 1) {
43 return this.bucketFor(userId).tryConsume(cost);
44 }
45}
46 
47const limiter = new RateLimiter({ capacity: 10, refillPerSecond: 2 });
48 
49export function rateLimit(req, res, next) {
50 const userId = req.user?.id ?? req.ip;
51 if (!limiter.allow(userId)) {
52 res.set('Retry-After', '1');
53 return res.status(429).json({ error: 'Too many requests' });
54 }
55 next();
56}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1The token bucket smooths bursts by allowing up to capacity requests instantly, then throttling to the refill rate.
  2. 2Computing refill lazily from elapsed time avoids running any background timer.
  3. 3Keying buckets by user in a Map isolates each caller's quota independently.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How token-bucket rate limiting works in Express — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code