Rate limiters
Use self-imposed rate limits to protect upstreams and your infrastructure. Define one or more "budgets" and assign them to project, network, upstream, or via authentication (per-user) overrides. Budgets are evaluated locally (in-process) using Envoy's ratelimit algorithm with either a Redis-backed shared store or a local memory store.
Config
# ...
projects:
- id: main
# ...
# A project can have a budget that applies to all requests (any network or upstream)
# Useful to prevent a project (e.g. frontend, or indexer) to send too much requests.
rateLimitBudget: frontend
# ...
# Each upstream can have its own budget
upstreams:
- id: blastapi-chain-42161
type: evm
endpoint: https://arbitrum-one.blastapi.io/xxxxxxx-xxxxxx-xxxxxxx
rateLimitBudget: global-blast
# ...
- id: blastapi-chain-1
type: evm
endpoint: https://eth-mainnet.blastapi.io/xxxxxxx-xxxxxx-xxxxxxx
rateLimitBudget: global-blast
# ...
- id: quiknode-chain-42161
type: evm
endpoint: https://xxxxxx-xxxxxx.arbitrum-mainnet.quiknode.pro/xxxxxxxxxxxxxxxxxxxxxxxx/
rateLimitBudget: global-quicknode
# ...
# Rate limiter allows you to create "shared" budgets for upstreams.
# For example upstream A and B can use the same budget, which means both of them together must not exceed the defined limits.
rateLimiters:
# Store is REQUIRED. Choose between redis (distributed) or memory (local-only)
store:
driver: redis # "redis" | "memory"
redis: # required when driver=redis
uri: redis://localhost:6379
username: "" # optional
# tls, pool, etc are supported via standard redis connector fields
budgets:
- id: frontend
rules:
- method: 'eth_trace*' # narrowest rule on top
maxCount: 5
period: second
perIP: true
- method: '*' # wildcard supported; checked per request method
maxCount: 20 # allowed count per period
period: second # one of: second, minute, hour, day, week, month, year
perIP: true
- id: global-blast
rules:
# You can limit which methods apply to this rule e.g. eth_getLogs or eth_* or * (all methods).
- method: '*'
maxCount: 1000
period: second
- method: '*'
maxCount: 5000000
period: day
- id: global-quicknode
rules:
- method: '*'
maxCount: 300
period: second
- method: '*'
maxCount: 1000000
period: dayAuto-tuner
The auto-tuner feature allows dynamic adjustment of rate limits based on the upstream's performance. It's particularly useful in the following scenarios:
- When you're unsure about the actual RPS limit imposed by the provider.
- When you need to update the limits dynamically based on the provider's current capacity.
The auto-tuner is enabled by default when an upstream has any rate limit budget defined. Here's an example configuration with explanations:
upstreams:
- id: example-upstream
type: evm
endpoint: https://example-endpoint.com
rateLimitBudget: example-budget
rateLimitAutoTune:
enabled: true # Enable auto-tuning (default: true)
adjustmentPeriod: "1m" # How often to adjust the rate limit (default: "1m")
errorRateThreshold: 0.1 # Maximum acceptable error rate (default: 0.1)
increaseFactor: 1.05 # Factor to increase the limit by (default: 1.05)
decreaseFactor: 0.9 # Factor to decrease the limit by (default: 0.9)
minBudget: 1 # Minimum rate limit (default: 0)
maxBudget: 10000 # Maximum rate limit (default: 10000)It's recommended to set minBudget to at least 1. This ensures that some requests are always routed to the upstream, allowing the auto-tuner to re-adjust if the provider can handle more requests.
The auto-tuner works by monitoring the "rate limited" (e.g. 429 status code) error rate of requests to the upstream. If the 'rate-limited' error rate is below the errorRateThreshold, it gradually increases the rate limit by the increaseFactor. If the 'rate-limited' error rate exceeds the threshold, it quickly decreases the rate limit by the decreaseFactor.
By default, the auto-tuner is enabled with the following configuration:
rateLimitAutoTune:
enabled: true
adjustmentPeriod: "1m"
errorRateThreshold: 0.1
increaseFactor: 1.05
decreaseFactor: 0.9
minBudget: 0
maxBudget: 10000You can override these defaults by specifying the desired values in your configuration.
Metrics
The following metrics are available for rate limiter budgets:
erpc_rate_limiter_budget_max_countwith labelsbudgetandmethod
This metrics shows how maxCount is adjusted over time if auto-tuning is enabled.
Where budgets can be applied
- Project:
project.rateLimitBudgetapplies to all requests within the project, across all networks and upstreams. - Network defaults:
networkDefaults.rateLimitBudgetprovides a default for all networks unless overridden per network. - Network:
network.rateLimitBudgetapplies to requests routed through that network. - Upstream:
upstream.rateLimitBudgetapplies to requests forwarded to that specific upstream (checked right before sending). - Auth strategy and per-user override:
- Each auth strategy can impose an additional budget before request handling:
- Secret:
auth.strategies[].secret.rateLimitBudget(static) - JWT: claim-based override. Default claim name
rlm, configurable viaauth.strategies[].jwt.rateLimitBudgetClaimName. If present, setsuser.rateLimitBudgetfor that request. - Database: a
rateLimitBudgetcolumn in your record setsuser.rateLimitBudget. - SIWE:
auth.strategies[].siwe.rateLimitBudget(static) - Network auth:
auth.strategies[].network.rateLimitBudget(static)
- Secret:
- Each auth strategy can impose an additional budget before request handling:
Budgets are composable: eRPC evaluates each applied layer independently (auth → project → network → upstream). If any layer returns over-limit, the request is rejected with a dedicated error indicating the layer, budget, and rule.
Rule scopes and descriptors
Rules can be evaluated with additional descriptors to partition rate usage:
perIP: true→ adds the client IP to the descriptor. Requires eRPC to determinereq.ClientIP()(via trusted proxy headers or remote addr).perUser: true→ adds the authenticated user ID. Requires an auth strategy to setuser.id.perNetwork: true→ adds the network ID being accessed.
Descriptor behavior:
- Scopes only affect partitioning of counters; they do not change
maxCount. - Combining scopes increases cardinality (e.g., perUser+perNetwork isolates usage per user per network).
- If a scoped value is missing (e.g.,
perUser: truebut unauthenticated), the rule will error for that request.
Example rule with scopes:
rateLimiters:
budgets:
- id: free-trial-package
rules:
- method: '*'
maxCount: 10
period: second
perUser: true # counts per authenticated user id
perNetwork: false # overall limit for each user
- method: '*'
maxCount: 20000
period: day
perUser: true # counts per authenticated user id
perNetwork: true # further partition per networkStore backends
-
Redis (recommended for multi-instance deployments):
- Strongly consistent counting across replicas.
- Configure via
rateLimiters.store.driver: redisandrateLimiters.store.redis(URI, TLS, pool size, etc.). nearLimitRatio(default 0.8) controls when "near limit" is reported internally.cacheKeyPrefix(defaulterpc_rl_) prefixes all ratelimit keys.
-
Memory (single-process only):
- Fast, in-memory counters. Not shared across processes.
- Good for development or single-node setups.
Matching and wildcards
rules[].methodsupports wildcards (*). Exact match or wildcard match triggers the rule.- Multiple rules can match a method; all matching rules are evaluated and any over-limit denies the request.
Evaluation order
For each request, eRPC may evaluate up to four layers (if configured):
- Auth layer (if the applied strategy defines a budget or the user provides an override via JWT/DB)
- Project layer
- Network layer
- Upstream layer
Each layer selects matching rules by method and checks counters via the configured store. The first layer that is over-limit stops processing and returns an error specific to that layer.
Errors and status codes
- Auth layer:
ErrAuthRateLimitRuleExceeded - Project layer:
ErrProjectRateLimitRuleExceeded - Network layer:
ErrNetworkRateLimitRuleExceeded - Upstream layer:
ErrUpstreamRateLimitRuleExceeded
Each error includes the budget ID and the rule (e.g., method:eth_getLogs) to aid debugging.
Defaults and validation
rateLimiters.storeis required. Allowed drivers:redis,memory.- Budgets must define at least one
rulesentry. periodmust be one of:second,minute,hour,day,week,month,year. Legacy durations like1sare accepted and mapped.- Upstream
rateLimitAutoTunedefaults on when a budget is set; you can tuneenabled,adjustmentPeriod,errorRateThreshold,increaseFactor,decreaseFactor,minBudget,maxBudget. - JWT budget claim defaults to
rlmand can be changed viaauth.strategies[].jwt.rateLimitBudgetClaimName.
Metrics
erpc_rate_limiter_budget_max_count{budget,method,scope}: current configured/auto-tuned max per rule.erpc_rate_limit_requests_total{budget,category,user,network}: local checks performed.erpc_rate_limit_within_limit_total{budget,category,user,network}: allowed by local limiter.erpc_rate_limit_over_limit_total{budget,category,user,network}: blocked by local limiter.erpc_auth_request_self_rate_limited_total{project,strategy,category}: auth layer over-limits.erpc_project_request_self_rate_limited_total{project,category}: project layer over-limits.
Operational notes
- Redis store is preferred for horizontal scaling; memory store is per-process only.
- Scopes that rely on request context (IP, user) require correct upstream proxy headers and a successful auth step.
- Wildcard-heavy rule sets are supported; prefer a small set of broad rules for performance and clarity.
- Auto-tuner adjusts only rules that match the method and have accumulated enough samples; set
minBudget >= 1so traffic never stops entirely.