# GCRA vs leaky / token buckets

DevFeed: [GCRA vs leaky / token buckets](<https://devfeed.tech/articles/gcra-vs-leaky-token-buckets-36228.md>)

Original publisher: [Read original article](<https://dotat.at/@/2026-01-15-gcra.html>)

Published: 2026-01-15T20:23:39Z

Content type: tutorial

Language: en

Sources: [Tony Finch's blog](<https://devfeed.tech/sources/tony-finch-s-blog.md>)

Topics: [Algorithms](<https://devfeed.tech/topics/algorithms.md>)

## AI overview

The note explains why the GCRA, leaky bucket, and token bucket rate-limiting algorithms behave equivalently, deriving the GCRA formulation into leaky bucket code through transformations.

## Source excerpt

In this note I'll show why the rate limit algorithms GCRA, leaky bucket, and token bucket behave the same. The parameters of the algorithms are a time window and a maximum quota of usage (e.g. requests or bytes) per window. The quota limits the size of a fast burst of requests. The maximum sustained rate is, rate = quota / window Leaky bucket and token bucket store the time of the previous request, and a bucket counting the available capacity. The rate determines how quickly capacity becomes available. It's easy to see that leaky bucket and token bucket are equivalent, because they simply count in opposite directions: leaky -= (now - previous) * rate leaky = clamp(0, leaky, quota) leaky += cost previous = now return leaky < quota ? ALLOW : DENY tokens += (now - previous) * rate tokens = clamp(0, tokens, quota) tokens -= cost previous = now return tokens > 0 ? ALLOW : DENY GCRA tracks a "not-before" time, and allows requests that occur after that point in time. The not-before time is normally in the recent past, and requests increase it towards and possibly (when the client is over its limit) beyond the present time. time = clamp(now - window, time, now) time += cost / rate return time < now ? ALLOW : DENY It's not trivially obvious that GCRA is equivalent to the other two. But we can convert the GCRA code into the leaky bucket code with a few transformations, as follows. We can change from absolute time to relative time by taking now away from the equations: bucket = clamp(-window, time, 0) bucket += cost / rate return bucket < 0 ? ALLOW : DENY But that change is incomplete: the stored bucket is relative to the time of the previous request. To make it relative to the current time, we need to remember when the previous request occurred, and after retrieving the bucket we need to shift it to account for the passage of time: bucket -= now - previous bucket = clamp(-window, time, 0) bucket += cost / rate previous = now return bucket < 0 ? ALLOW : DENY Now we will change