Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 2 min read

Rate limiting algorithms explained: Token Bucket vs Sliding Window vs Fixed Window

Rate limiting sounds simple: count requests, block when over the limit. But the algorithm you choose changes how your API behaves under load. Here's what's actually happening. Fixed Window The simplest algorit

Rate limiting sounds simple: count requests, block when over the limit.
But the algorithm you choose changes how your API behaves under load.
Here's what's actually happening.

Fixed Window

The simplest algorithm. Count requests in a fixed time window (e.g. 60
seconds). When the counter hits the limit, block until the window resets.

Window: [0s -------- 30s -------- 60s]
Requests:  1  2  3  4  5 ... 30 = DENY
                                        Window resets
Requests:  1  2  3  4  5 ... 30 = DENY

Problem: boundary spikes. If the limit is 30/minute and a client sends
30 requests at 59s and 30 at 61s, they got 60 requests in 2 seconds.

Use when: login protection, payment endpoints, strict quotas.

Token Bucket

Each client gets a bucket of tokens. Tokens refill at a constant rate.
Each request costs one token. If the bucket is empty, the request is denied.

Bucket: [========] 8/10 tokens
Request costs 1 token β†’ [=======] 7/10
Refill 1 token/sec   β†’ [========] 8/10 (after 1s)

Key property: allows bursts. If you haven't made requests for a while,
your bucket fills up and you can burst above the average rate.

Use when: general API protection, where short bursts are acceptable.

Sliding Window

Like Fixed Window, but the window slides continuously. Instead of counting
in a fixed block, it counts requests in the last N seconds.

Window:   [------======------]
           now-60s   now
Requests:  1  2  3  4  5  6 = 6 in last 60s

Key property: no boundary spikes. Smooth rate limiting.

Use when: fair API usage, where you want consistent behavior.

GCRA (Generic Cell Rate Algorithm)

Used in telecom networks. Instead of counting requests, it tracks the
"theoretical arrival time" of the next allowed request.

Key property: very smooth, memory-efficient, no bucket to overflow.

Use when: high-throughput APIs, telecom-grade traffic shaping.

Leaky Bucket

Requests enter a bucket that leaks at a constant rate. If the bucket
overflows, requests are denied. Output is constant-rate regardless of
input spikes.

Input:   [======]   (burst)
Bucket:  [====]     (buffered)
Output:  [=]        (constant rate)

Use when: background jobs, queues, APIs that need constant processing rate.

Side-by-side

Token Bucket Fixed Window Sliding Window GCRA Leaky Bucket
Bursts allowed Yes No No No No
Boundary spikes No Yes No No No
Memory per key Low Very low Medium Very low Low
Smoothness Medium Low High Very high High
Complexity Medium Low Medium Medium Medium

The choice matters

Most rate limiters default to Fixed Window because it's simple. But Fixed
Window has the boundary spike problem: a clever client can get 2x the limit
by timing requests around the window boundary.

Token Bucket is usually the better default: it allows natural bursts while
still enforcing the average rate. If you need strict quotas (no bursts at
all), use Fixed Window explicitly.

In Python

from drogue.core.rules.rule import AlgorithmType

# Burst-friendly (default)
@limiter.limit("30/minute")

# Strict per-window quota
@limiter.limit("30/minute", algorithm=AlgorithmType.FIXED_WINDOW)

# Smooth, no boundary spikes
@limiter.limit("30/minute", algorithm=AlgorithmType.SLIDING_WINDOW)

All five algorithms are available. Pick based on your traffic pattern.

Full algorithm docs |
drogue on GitHub

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.