Rate limits#
The public BSR at buf.build applies rate limits to all traffic, regardless of the user’s plan.
Pro and Enterprise dedicated instances aren’t configured with rate limits, so high-volume production workloads usually run there.
Limits below reflect current policy; specific numbers can change.
Where rate limits apply#
- Public BSR (
buf.build): all traffic is subject to the limits below, regardless of plan. - Pro dedicated instances (
<org>.buf.dev) and Enterprise instances: no rate limits under current configuration.
How counting works#
Each request lands in exactly one bucket, chosen by URL prefix. Buckets use a GCRA leaky-bucket model with two parameters: a sustained rate (the long-run cap) and a burst (the short-run pool that refills at the sustained rate).
Identity attribution depends on whether the request is authenticated:
- Authenticated requests (a valid BSR Bearer token in
Authorization) are counted per BSR user. - Unauthenticated requests are counted per source IP.
Limits#
| Bucket | Sustained rate | Burst |
|---|---|---|
| General API | 30 req/sec | 60 |
| Code generation, unauthenticated | 10 req/hour | 10 |
| Code generation, authenticated | 960 req/hour | 120 |
FileDescriptorSetService |
1 req/sec | 2 |
General API#
Most BSR calls land here, including buf push, dependency resolution and module download (buf dep update, buf build against a remote module), and plugin metadata queries.
The bucket is shared across these endpoints; it isn’t a per-service limit.
Code generation#
Remote code generation calls (the CodeGenerationService.GenerateCode RPC, which is what buf generate triggers when configured with remote plugins) use the dedicated code-generation bucket.
This is the only bucket with separate authenticated and unauthenticated tiers; authenticating raises the limit roughly 100×.
Each buf generate invocation counts as one request against the bucket, regardless of how many remote plugins it runs, up to a hard ceiling of 20 plugins per request:
buf.gen.yamlwith 15 remote plugins → 1 request, accepted.buf.gen.yamlwith 22 remote plugins → rejected.
To authenticate the Buf CLI, see Authentication.
FileDescriptorSetService#
Calls to buf.reflect.v1beta1.FileDescriptorSetService use a more specific carve-out instead of the General API bucket; the lower rate isn’t stacked on top of the General API limit.
Response headers#
Every BSR response carries the current rate-limit state:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Total requests allowed in the current window. |
X-RateLimit-Remaining |
Requests still available before the bucket is empty. |
X-RateLimit-Reset |
Seconds until the bucket fully refills. |
Retry-After |
Set on rate-limited responses; seconds to wait before retrying. |
Handling 429 responses#
A request that exceeds its bucket returns HTTP 429 with X-RateLimit-Remaining: 0, the Connect error code resource_exhausted, and a Retry-After header.
Recommended client behavior:
- Honor
Retry-After. The value reflects when the bucket will admit the next request, so retrying earlier just produces another 429. - Use exponentially increasing delays between retries if
Retry-Afterisn’t available to your client (some only surface the status code). - If a request is part of an interactive workflow, surface the
X-RateLimit-Resetvalue to the user instead of silently retrying.
Raising your limits#
- Authenticate. A valid BSR token raises the code-generation bucket from 10 req/hour to 960 req/hour. The General API and
FileDescriptorSetServicebuckets don’t have an authenticated tier; authenticating doesn’t change them. - Move production traffic to a dedicated instance. Pro and Enterprise instances aren’t subject to the limits above.
- Contact us if you’re hitting limits on a workload that doesn’t fit the patterns above.