throttled/throttled for Go HTTP rate limiting
Package throttled implements rate limiting access to resources such as HTTP endpoints.
At a glance
- What is it?
- throttled is a Go package that applies GCRA rate limits to resources such as HTTP handlers, with in-memory and Redis-backed stores. It fits applications that need per-path quotas and short bursts, but its documented example leaves production policy decisions to the caller.
- Who is it for?
- Go services that need a library-level GCRA limiter should first verify the store topology, quota calculation, VaryBy key, and context-aware APIs against their deployment. It is less suitable for teams needing documented production defaults, built-in response headers, or a complete gateway.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Where throttled fits in a Go service
throttled addresses one specific problem: limiting how often callers can access a resource. The repository describes HTTP endpoints as its main example, but its quota and store abstractions are not tied to HTTP alone. The intended audience is a Go developer who already has an application handler and needs rate control inside that process, rather than a separate gateway configured in front of the service.
That distinction matters because throttled does not present itself as a complete API gateway. The README supplies `HTTPRateLimiterCtx`, quota configuration, key selection through `VaryBy`, and storage, but it does not document retry headers, distributed deployment instructions, configuration files, metrics, or response policies. Developers still need to decide what should happen after a limit is reached and how callers should be identified. In the shown example, the quota is scoped by URL path. The handler does not vary by client address or another request attribute.
The package uses the Generic Cell Rate Algorithm, or GCRA. A `RateQuota` supplies `MaxRate` and `MaxBurst`, and `NewGCRARateLimiterCtx` turns those values into the limiter used by the HTTP adapter. The separate HTTP layer wraps an ordinary `http.Handler`. This design makes the limiter usable as Go middleware without requiring a particular web framework.
GCRA quota and HTTPLimiterCtx request flow
The request path is explicit in the README example. First, the application creates a store with `memstore.NewCtx(65536)`. Next, it declares a quota of 20 requests per minute and a maximum burst of 5. `throttled.NewGCRARateLimiterCtx` receives the store and quota. The application then places that limiter inside `HTTPRateLimiterCtx` and calls `RateLimit(handler)`.
`VaryBy` determines what distinguishes one rate bucket from another. The example sets `Path: true`, so requests are grouped according to their paths. The README does not specify the exact key serialization or the complete set of defaults, so implementation-sensitive details should be checked in the package documentation and source. It is also important not to assume that path-only scoping is appropriate for every service. If a public endpoint has several callers, path-based buckets can combine traffic from different clients unless the application configures another key dimension that supports its policy.
The context-aware constructor names are deliberate. The upgrade notes map old APIs to newer equivalents, including `memstore.NewCtx`, `NewGCRARateLimiterCtx`, and `HTTPRateLimiterCtx`. A new integration should use the context-aware versions from the start. However, the README warns that not all stores yet use the supplied `context.Context`, so the suffix alone does not prove that a backend handles cancellation or deadlines.
Installing throttled with Go Modules
The project requires Go Modules, and the README tells users to confirm that the consuming package has a `go.mod` file. The module path includes the major version as `/v2`, which keeps imports aligned with the package's semantic version. Standard Go tooling can then discover the dependency.
Install or update the module with the command documented by the project:
go get -u github.com/throttled/throttled/v2The import path shown in the README is:
import (
"github.com/throttled/throttled/v2"
)The repository's `go.mod` declares Go 1.18 and identifies the module as `github.com/throttled/throttled/v2`. Its dependencies include Redis clients, Redigo, an LRU package, Testify, and OpenTelemetry-related modules. This dependency list indicates that `go.mod` covers stores and tests beyond the minimal memory-store example. The README does not document a separate runtime service to install.
An upgrade from the pre-Modules version has one unavoidable source change: add `/v2` to existing imports. The README says the current code is otherwise compatible with that version. It does not provide an automated migration command.
Configuring the first HTTP limiter
The first complete use is the README's HTTP server example. The configuration can be split into a quota declaration and limiter construction. The quota below permits 20 requests per path per minute, with bursts of up to 5 additional requests.
quota := throttled.RateQuota{
MaxRate: throttled.PerMin(20),
MaxBurst: 5,
}
rateLimiter, err := throttled.NewGCRARateLimiterCtx(store, quota)The surrounding application must create `store` before this block and handle the constructor error. The complete README example uses `memstore.NewCtx(65536)` and passes its result to the limiter constructor. The store size is therefore a concrete configuration choice, although the README does not explain the eviction or capacity semantics of that argument.
After constructing the rate limiter, wrap the destination handler:
httpRateLimiter := throttled.HTTPRateLimiterCtx{
RateLimiter: rateLimiter,
VaryBy: &throttled.VaryBy{Path: true},
}
handler := http.HandlerFunc(myHandlerFunc)Passing `httpRateLimiter.RateLimit(handler)` to `http.ListenAndServe(":8080", ...)` connects the policy to the server. The README's handler responds with `Hello, world`; it does not show a custom rejected-request handler or logging. For a first local use, the visible criterion is that the wrapped server starts on port 8080 and passes the README's plain text response while enforcing the configured limiter.
Memory and Redis store boundaries
The README example uses `memstore`, but the module also depends on several Redis client libraries, and its upgrade notes name `goredisstore.NewCtx` and `redigostore.NewCtx` as context-aware alternatives. That points to more than one storage model. It does not provide enough documentation here to compare their exact eviction, expiry, serialization, failure, or Redis Cluster behavior.
This distinction affects adoption. A memory store is a direct choice for a single Go process, while a shared Redis store can be relevant when rate state must be visible across instances. The repository names those backends, but it does not state that every Redis implementation has identical semantics or operational behavior. An engineer selecting a distributed store would need to inspect that store's package documentation and determine how its keys represent quotas and expirations.
There is another boundary in the API naming. Constructors and middleware have context-aware variants, but the README explicitly notes that not every store uses the passed context yet. That makes context propagation an adoption check rather than a blanket guarantee. The README does not document retry behavior when a shared store is unavailable, nor does it establish that the limiter fails open or fails closed. No such failure policy should be inferred.
Limits of the documented integration
The clearest limitation is missing operational policy. The example creates a limiter, but it does not state which HTTP status or response body a rejected caller receives. It also does not show standard rate-limit headers, logging hooks, metrics, or an administrative endpoint. A service that needs those behaviors must inspect the API and compose them around the middleware rather than expecting the README example to supply them.
Path-based bucketing can also be the wrong choice for a multi-tenant endpoint. Since the example enables `Path`, it groups requests using the path alone. The README does not show a configuration that includes authenticated identity, API key, IP address, or tenant ID. Selecting the key is security-relevant policy work: a bucket that is too broad can let one caller consume another caller's allowance, while a bucket based on attacker-controlled input can create excessive cardinality. The repository supports variation through `VaryBy`, but the README does not explain every available field.
A second limitation is operational transparency. There is no documented persistence or availability target for `memstore`, and no Redis deployment example. That makes throttled a code-level component rather than a documented distributed rate-limiting service. It is a poor fit if the requirement is to deploy a gateway with predefined global quotas and centralized policy.
Throttled compared with external gateway enforcement
A real alternative is enforcing limits at an HTTP gateway or reverse proxy. The difference in approach is placement. Throttled runs inside the Go process, wraps an `http.Handler`, and keeps policy close to application code. A gateway applies limits before requests reach the application, using its own configuration, shared state, and response handling.
The gateway approach can fit deployments where several services need one centrally configured boundary. Throttled fits codebases that need policy tied to a particular handler or Go object and are comfortable adding an in-process component to the request path. The README does not claim feature parity with a gateway, so the choice should not be framed as a library versus a complete gateway feature checklist. It is an in-process middleware decision versus an infrastructure decision.
For throttled, first verify the store and key model. For a gateway, first verify how it stores counters across replicas and what it does when its state backend fails. Those checks are more concrete than a generic claim about either option being better. throttled also identifies `throttled/gcra` as a related project for finding other GCRA and rate-limiting implementations, but it does not document how those alternatives differ.
Maintenance, Go versions, and licensing
The repository is not archived. Its last push was on 2026-04-13, and the listed releases include v2.15.0 on 2025-08-23, v2.14.0 on 2025-08-23, and v2.13.0 on 2025-01-23. The release process in the README requires updating `CHANGELOG.md`, tagging `master` with a version such as `v2.2.0`, pushing tags, and publishing a release with notes copied from the changelog.
The module declares Go 1.18. Upgrading consumers therefore includes accounting for the Go toolchain version and reviewing dependency changes in `go.mod` and `go.sum`. The README also records a migration from pre-Modules Throttled, which requires adding `/v2` to imports. That is a small source edit, but an application with many imports may have multiple files to change.
Throttled uses the BSD 3-Clause license, with copyright attributed to Martin Angers and contributors. That identifier describes the project's published licensing terms; this review does not provide legal advice. The repository's own license file remains the source to consult when assessing distribution or compliance requirements.
Editorial conclusion
Go services that need a library-level GCRA limiter should first verify the store topology, quota calculation, VaryBy key, and context-aware APIs against their deployment. It is less suitable for teams needing documented production defaults, built-in response headers, or a complete gateway. For a small service, the README demonstrates a 20 requests per minute limit with up to 5 additional requests per path. For a distributed deployment, confirm that the selected store gives each request a consistent view of rate state.
Frequently asked questions
What algorithm does throttled use for Go rate limiting?
The package uses the Generic Cell Rate Algorithm. Its example configures this algorithm through `NewGCRARateLimiterCtx`, with a `RateQuota` containing `MaxRate` and `MaxBurst`.
How do I install throttled in a Go project?
Go Modules are required. Run `go get -u github.com/throttled/throttled/v2`, then import `github.com/throttled/throttled/v2`; standard Go tooling will resolve the dependency.
Does throttled provide a context-aware API?
Yes. The README identifies context-aware equivalents including `memstore.NewCtx`, `NewGCRARateLimiterCtx`, and `HTTPRateLimiterCtx`. It also warns that not all stores use the supplied `context.Context` yet.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/throttled-throttled)Was this useful?