The leaky bucket algorithm takes traffic that arrives in unpredictable bursts and turns it into output that leaves at a constant, predictable rate — the same way an actual bucket with a hole in the bottom drains at a fixed pace no matter how fast or slow you pour water in. It is one of the older ideas in networking, dating back to traffic shaping in packet-switched networks, and it is still the right choice whenever the goal is a steady output rate rather than simply capping how much gets through.
What changed in 2026
- Cloud API gateways now expose traffic "smoothing" as a first-class configuration option, distinct from a hard rate cap, which is the leaky bucket's defining behavior surfacing directly in provider dashboards.
- Edge and serverless platforms increasingly apply it before a request ever reaches application code, shaping bursty client traffic into a steady stream before it hits a backend that cannot absorb spikes.
- Renewed relevance came from AI inference traffic, where smoothing bursty request patterns into a constant rate protects downstream model-serving capacity that cannot be scaled instantly.
The bucket-and-hole model
Picture a bucket that leaks at a fixed rate — say, one unit per second — regardless of how much is currently in it. Incoming requests add to the bucket. If the bucket is not full, the request is accepted and queued for processing at the leak rate. If the bucket is already full, the new request overflows and is dropped or rejected. The bucket's capacity absorbs short bursts; the leak rate determines the maximum sustained output, and that output rate never varies based on input pattern.
Leaky bucket as a meter vs as a queue
| Implementation |
How it behaves |
Best for |
| As a meter (counter) |
Tracks a virtual fill level that decays over time; rejects requests that would overflow it |
Rate limiting where excess requests should simply be rejected |
| As a queue |
Holds accepted requests and releases them at the leak rate in order |
Traffic shaping where smoothing output matters more than immediate rejection |
Pseudocode
class LeakyBucket:
def __init__(self, capacity, leak_rate):
self.capacity = capacity
self.leak_rate = leak_rate # units per second
self.level = 0
self.last_check = time.now()
def allow(self):
now = time.now()
elapsed = now - self.last_check
self.level = max(0, self.level - elapsed * self.leak_rate)
self.last_check = now
if self.level + 1 <= self.capacity:
self.level += 1
return True
return False
Where it is used
Traffic shaping at network egress points, where a fixed downstream link should never see a burst larger than it can absorb; API gateways protecting a backend that processes requests at a roughly constant rate regardless of client-side burstiness; and queueing systems where consumers pull work at a steady pace and producers should be smoothed to match, rather than being allowed to flood the queue.
Leaky bucket vs token bucket, briefly
The two are often confused because both use a "bucket" metaphor for rate limiting, but they behave differently under burst conditions: a leaky bucket enforces a flat output rate no matter what, while a token bucket allows a burst up to its capacity before falling back to the steady rate. See rate limiting strategies for a full side-by-side comparison, and the token bucket algorithm for the burst-friendly alternative.
Common pitfalls
Using it where bursts should be allowed. If legitimate clients occasionally need to send a quick burst — a page loading a dozen resources at once, for instance — a flat leaky bucket punishes normal behavior. A token bucket handles that case better.
Sizing the bucket capacity too small. A tiny capacity makes even minor timing jitter look like an overflow, causing rejections under perfectly normal load.
Forgetting the leak happens continuously, not in discrete steps. An implementation that only leaks at fixed intervals rather than continuously can behave unexpectedly right at the boundary of each interval.
FAQ
Does a leaky bucket ever allow bursts?
Only up to its capacity, and even then the output rate stays fixed — the capacity absorbs a burst on the input side, but the drain rate never speeds up to clear it faster.
Is leaky bucket the same as a queue with a rate limiter?
The queue implementation of a leaky bucket essentially is that — a bounded queue drained at a constant rate. The meter implementation achieves the same effect without literally queueing anything.
Why would I pick leaky bucket over a simple fixed-window counter?
A fixed-window counter allows a full burst right at the boundary between two windows, effectively doubling the momentary rate. A leaky bucket has no such boundary effect because it smooths continuously.
Is this still relevant, or has it been replaced by newer algorithms?
It remains relevant specifically because it is still the simplest way to guarantee a constant output rate. Newer approaches address different goals, like allowing controlled bursts, rather than replacing this one outright.
Where to go next