Skip to content

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.yaml with 15 remote plugins → 1 request, accepted.
  • buf.gen.yaml with 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-After isn’t available to your client (some only surface the status code).
  • If a request is part of an interactive workflow, surface the X-RateLimit-Reset value 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 FileDescriptorSetService buckets 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.