Config
Upstreams

Upstreams

An upstream is defined to handle 1 or more networks (a.k.a. chains). There are currently these types of upstreams:

  • evm A generic EVM-compatible JSON-RPC endpoint. This is the default and most-used type.
  • alchemy Accepts alchemy.com api key and automatically adds all their EVM chains.
  • drpc Accepts drpc.org api key and automatically adds all their EVM chains.
  • blastapi Accepts blastapi.io api key and automatically adds all their EVM chains.
  • thirdweb Accepts thirdweb.com client-id and automatically adds all their EVM chains.
  • envio Accepts envio.dev rpc endpoint and automatically adds all chains by HyperRPC.
  • pimlico Accepts pimlico.io rpc endpoint for account-abstraction (ERC-4337) support.
  • etherspot Accepts etherspot.io rpc endpoint for account-abstraction (ERC-4337) support.
  • infura Accepts infura.io api key and automatically adds all their EVM chains.

eRPC supports any EVM-compatible JSON-RPC endpoint when using evm type. Specialized types like "alchemy" are built for well-known providers to make it easier to import "all supported evm chains" with just an API-KEY.

Config

erpc.yaml
# ...
projects:
  - id: main
    # ...
 
    # Each upstream supports 1 or more networks (i.e. evm chains)
    upstreams:
      # (REQUIRED) Endpoint URL supports http(s) scheme along with custom schemes like "alchemy://" defined below in this docs.
      - endpoint: https://arbitrum-one.blastapi.io/xxxxxxx-xxxxxx-xxxxxxx
 
        # Each upstream can have an arbitrary group name which is used in metrics, as well as 
        # useful when writing an eval function in selectionPolicy below.
        # Use "fallback" group to let eRPC automatically create a "default" selection policy on the network level
        # and then fallback to this group if the default one doesn't have enough healthy upstreams.
        group: fallback
        
        # (OPTIONAL) Upstream ID is optional and can be used to identify the upstream in logs/metrics.
        id: blastapi-chain-42161
 
        # (OPTIONAL) Configurations for EVM-compatible upstreams.
        evm:
          # (OPTIONAL) chainId is optional and will be detected from the endpoint (eth_chainId),
          # but it is recommended to set it explicitly, for faster initialization. 
          # DEFAULT: auto-detected.
          chainId: 42161
          # (OPTIONAL) statePollerInterval used to periodically fetch the latest/finalized/sync states.
          # DEFAULT: 30s.
          statePollerInterval: 30s
          # (OPTIONAL) nodeType is optional and you can manually set it to "full" or "archive".
          # DEFAULT: archive
          nodeType: full
          # (OPTIONAL) maxAvailableRecentBlocks limits the maximum number of recent blocks to be served by this upstream.
          # DEFAULT: 128 (for "full" nodes).
          maxAvailableRecentBlocks: 128
          # (OPTIONAL) fallbackFinalityDepth is optional and allows to manually set the finality depth.
          # DEFAULT: <none> - eRPC will auto-detect via eth_getBlockByNumber(finalized).
          fallbackFinalityDepth: 1024
 
        # (OPTIONAL) Defines which budget to use when hadnling requests of this upstream (e.g. to limit total RPS)
        # Since budgets can be applied to multiple upstreams they all consume from the same budget.
        # For example "global-blast" below can be applied to all chains supported by BlastAPI,
        # to ensure you're not hitting them more than your account allows.
        # DEFAULT: <none> - no budget applied.
        rateLimitBudget: global-blast
 
        # (OPTIONAL) Rate limit budget can be automatically adjusted based on the "rate-limited" error rate,
        # received from upstream. Auto-tuning is enabled by default with values below.
        # This is useful to automatically increase the budget if an upstream is capable of handling more requests,
        # and decrease the budget if upstream is degraded.
        # Every "adjustmentPeriod" total number of requests vs rate-limited will be calculated,
        # if the value (0 to 1) is above "errorRateThreshold" then budget will be decreased by "decreaseFactor",
        # if the value is below "errorRateThreshold" then budget will be increased by "increaseFactor".
        # Note that the new budget will be applied to any upstream using this budget (e.g. Quicknode budget decreases).
        # DEFAULT: if any budget is defined, auto-tuning is enabled with these values:
        rateLimitAutoTune:
          enabled: true
          adjustmentPeriod: 1m
          errorRateThreshold: 0.1
          increaseFactor: 1.05
          decreaseFactor: 0.9
          minBudget: 0
          maxBudget: 10_000
 
        # (OPTIONAL) To allow auto-batching requests towards the upstream.
        # Remember even if "supportsBatch" is false, you still can send batch requests to eRPC
        # but they will be sent to upstream as individual requests.
        jsonRpc:
          supportsBatch: true
          batchMaxSize: 10
          batchMaxWait: 50ms
 
        # (OPTIONAL) Which methods must never be sent to this upstream.
        # For example this can be used to avoid archive calls (traces) to full nodes
        ignoreMethods:
          - "eth_traceTransaction"
          - "alchemy_*"
        # (OPTIONAL) Explicitly allowed methods will take precedence over ignoreMethods.
        # For example if you only want eth_getLogs to be served, set ignore methods to "*" and allowMethods to "eth_getLogs".
        allowMethods:
          - "eth_getLogs"
        # (OPTIONAL) By default a dynamic mechanism automatically adds "Unsupported" methods to ignoreMethods,
        # based on errors returned by the upstream. Set this to false to disable this behavior.
        # Default: true
        autoIgnoreUnsupportedMethods: true
 
        # (OPTIONAL) Refer to "Failsafe" docs section for more details.
        # Here is "default" configuration if not explicitly set:
        failsafe:
          timeout:
            duration: 15s
          retry:
            maxAttempts: 2
            delay: 1000ms
            backoffMaxDelay: 10s
            backoffFactor: 0.3
            jitter: 500ms
          circuitBreaker:
            # Open circuit after 80% of requests so far have failed (160 out of 200 last requests)
            failureThresholdCount: 160 
            failureThresholdCapacity: 200
            # Wait 5 minutes before trying again
            halfOpenAfter: 5m
            # Close circuit after 3 successful requests (3 out of 10)
            successThresholdCount: 3
            successThresholdCapacity: 10

Config defaults

The project.upstreamDefaults configuration allows you to set default values for all upstreams in a project. These defaults are applied before any upstream-specific configurations:

erpc.yaml
projects:
  - id: main
    
    upstreams:
      # ... example above ^
    
    upstreamDefaults:
      # Default group for all upstreams
      group: "default"
      
      # Default JSON-RPC settings
      jsonRpc:
        supportsBatch: true
        batchMaxSize: 10
        batchMaxWait: "50ms"
      
      # Default failsafe policies
      failsafe:
        timeout:
          duration: "15s"
        retry:
          maxAttempts: 3
          delay: "300ms"
          jitter: "100ms"
          backoffMaxDelay: "5s"
          backoffFactor: 1.5
        circuitBreaker:
          failureThresholdCount: 160
          failureThresholdCapacity: 200
          halfOpenAfter: "5m"
          successThresholdCount: 3
          successThresholdCapacity: 3
 
      # Default method filters
      ignoreMethods:
        - "eth_traceTransaction"
        - "alchemy_*"
      allowMethods:
        - "eth_getLogs"

Default values are only applied if the upstream doesn't have those values explicitly set. This allows you to have consistent configuration across all upstreams while still maintaining the ability to override specific values when needed.

Defaults are merged on the first-level only (and not a deep merge).
i.e. If an upstream has its own failsafe: defined, it will not take any of policies from upstreamDefaults.
e.g. if an upstream.failsafe only has "timeout" policy, it will NOT get retry/circuitBreaker from upstreamDefaults (those will be disabled).

Priority & selection mechanism

eRPC evaluates each upstream's performance using key metrics to decide the most suitable upstream for each request. These metrics include:

  • Total request failures: Prioritizes upstreams with lower failure rates.
  • Rate-limited requests: Gives preference to upstreams with fewer rate-limited requests.
  • P90 request latency: Prioritizes upstreams with lower latency.
  • Total requests served: Favors upstreams that have served fewer requests to balance load.
  • Block head lag: Prefers upstreams with lower lag compared to the best-performing upstream.
  • Finalization lag: Prioritizes upstreams with lower finalization lag.

Each upstream receives a score based on these metrics, calculated per method (e.g., eth_blockNumber, eth_getLogs) over a configurable time window (windowSize, default 30 minutes). Adjust the window size in erpc.yaml as shown:

erpc.yaml
projects:
  # ...
  - id: main
    # ...
    healthCheck:
      scoreMetricsWindowSize: 1h
      # ...

The scoring mechanism only affects the order in which upstreams are tried. To fully disable an unreliable upstream, use the Circuit Breaker (opens in a new tab) failsafe policy at the upstream level.

Customizing scores & priorities

Upstreams are ranked by score, controlling selection order. You can adjust this ranking by setting multipliers at different levels: overall, per network or method, or for specific metrics (e.g., error rate, block lag).

erpc.yaml
upstreams:
  # ...
  - id: my-alchemy
    # ...
    routing:
      scoreMultipliers:
        - network: '*' # Relevant when upstream supports multiple networks (default: all networks)
          method: '*' # Method(s) where you want to apply these multipliers (default: all methods)
          # method: 'eth_*|alchemy_*' means apply these multipliers to all methods starting with "eth_" or "alchemy_"
 
          # (OPTIONAL) Adjusts the overall score scale.
          # DEFAULT: 1.0
          overall: 1.0
          
          # (OPTIONAL) Default multiplier values:
          errorRate: 8.0       # Penalize higher error rates by increasing this value.
          p90latency: 4.0      # Penalize higher latency by increasing this value.
          totalRequests: 1.0   # Give more weight to upstreams with fewer requests.
          throttledRate: 3.0   # Penalize higher throttled requests by increasing this value.
          blockHeadLag: 2.0    # Penalize nodes lagging in block head updates by increasing this value.
          finalizationLag: 1.0 # Penalize nodes lagging in finalization by increasing this value.

Example: To prioritize a less expensive (but slower) upstream, adjust the overall score multiplier as follows:

erpc.yaml
upstreams:
  # ...
  - id: my-cheap-node
    # ...
    routing:
      scoreMultipliers:
        - overall: 10
  - id: my-expensive-node
    # ...
    routing:
      scoreMultipliers:
        - overall: 1

A higher score means the upstream is tried first. If errors occur, other upstreams are attempted.

Upstream types

evm

These are generic well-known EVM-compatible JSON-RPC endpoints. This is the default and most-used type. They can be your own self-hosted nodes, or remote 3rd-party provider nodes.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: my-infura
        type: evm
        endpoint: https://mainnet.infura.io/v3/YOUR_INFURA_KEY
 
        # (OPTIONAL) Configurations for EVM-compatible upstreams.
        evm:
          # (OPTIONAL) chainId is optional and will be detected from the endpoint (eth_chainId),
          # but it is recommended to set it explicitly, for faster initialization. 
          # DEFAULT: auto-detected.
          chainId: 42161
          # (OPTIONAL) statePollerInterval used to periodically fetch the latest/finalized/sync states.
          # To disable state polling set this value to 0, which means no regular calls to RPC for latest/finalized/sync states.
          # The consequence of this is all data will be considered "unfinalized" or "unknown" despite their block numbers (and where if theye're actually finalized or not).
          # DEFAULT: 30s.
          statePollerInterval: 30s
          # (OPTIONAL) nodeType is optional and you can manually set it to "full" or "archive".
          # DEFAULT: archive
          nodeType: full
          # (OPTIONAL) maxAvailableRecentBlocks limits the maximum number of recent blocks to be served by this upstream.
          # DEFAULT: 128 (for "full" nodes).
          maxAvailableRecentBlocks: 128
        # ...

alchemy

This upstream type is built specially for Alchemy (opens in a new tab) 3rd-party provider to make it easier to import "all supported evm chains" with just an API-KEY.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: my-alchemy
        endpoint: alchemy://YOUR_ALCHEMY_API_KEY
        # ...

drpc

This upstream type is built specially for dRPC (opens in a new tab) 3rd-party provider to make it easier to import "all supported evm chains" with just an API-KEY.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: my-drpc
        endpoint: drpc://YOUR_DRPC_API_KEY
        # ...

blastapi

This upstream type is built specially for BlastAPI (opens in a new tab) 3rd-party provider to make it easier to import "all supported evm chains" with just an API-KEY.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: my-blastapi
        endpoint: blastapi://YOUR_BLASTAPI_API_KEY
        # ...

infura

This upstream type is built specially for Infura (opens in a new tab) 3rd-party provider to make it easier to import "all supported evm chains" with just an API-KEY.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: my-infura
        endpoint: infura://YOUR_INFURA_API_KEY
        # ...

thirdweb

This upstream type is built specially for Thirdweb (opens in a new tab) 3rd-party provider to make it easier to import "all supported evm chains" with just a CLIENT-ID.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: my-thirdweb
        endpoint: thirdweb://YOUR_THIRDWEB_CLIENT_ID
        # ...

For production traffic consult with Thirdweb team about the chains you are goin to use and amount of traffic you expect to handle.

envio

Envio HyperRPC (opens in a new tab) service provides a higher-performance alternative for certain read methods. When handling requests if a method is supported by HyperRPC (opens in a new tab), then this upstream may be used.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: envio-public
        endpoint: envio://rpc.hypersync.xyz
        # ...

For indexing use-cases it is recommended to this upstream. This will automatically add all supported EVM chains by HyperRPC.

pimlico

Pimlico (opens in a new tab) adds account-abstraction (ERC-4337) support to your eRPC instance. With this upstream added when a AA-related request arrives it'll be forwarded to Pimlico, which allows you to use the same RPC endpoint for both usual eth_* methods along with ERC-4337 methods.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: pimlico-public
        endpoint: pimlico://public
        # Or provide your API-KEY as:
        # endpoint: pimlico://xxxxxmy-api-key
        # ...

etherspot

Etherspot (opens in a new tab) adds account-abstraction (ERC-4337) support to your eRPC instance. With this upstream added when a AA-related request arrives it'll be forwarded to Etherspot, which allows you to use the same RPC endpoint for both usual eth_* methods along with ERC-4337 methods.

erpc.yaml
# ...
projects:
  - id: main
    # ...
    upstreams:
      - id: etherspot-public
        endpoint: etherspot://public
        # Or provide your API-KEY as:
        # endpoint: etherspot://xxxxxmy-api-key
        # ...

Compression

eRPC supports gzip compression at multiple points in the request/response cycle:

  1. Client → eRPC: Clients can send gzipped requests by setting Content-Encoding: gzip header
# Example of sending gzipped request to eRPC
curl -X POST \
  -H "Content-Encoding: gzip" \
  -H "Content-Type: application/json" \
  --data-binary @<(echo '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[]}' | gzip) \
  http://localhost:4000/main/evm/42161
  1. eRPC → Upstream: Configurable per upstream to send gzipped requests (disabled by default)
erpc.yaml
upstreams:
  - id: my-infura
    jsonRpc:
      enableGzip: false  # gzip when sending requests to this upstream (disabled by default)
  1. Upstream → eRPC: Automatically handles gzipped responses from upstreams when they send Content-Encoding: gzip

  2. eRPC → Client: Automatically enabled when clients send Accept-Encoding: gzip header (can be disabled in server config)

erpc.yaml
server:
  enableGzip: true  # gzip compression for responses to clients (enabled by default)

Using gzip can reduce ingress/egress bandwidth costs, and in certain cases (e.g. large RPC requests) it can improve performance.

Roadmap

On some doc pages we like to share our ideas for related future implementations, feel free to open a PR if you're up for a challenge:


  • Automatically detect type of EVM nodes (full, archive) and engines (erigon, geth, etc)
  • Implement the logic for "getLogsMaxBlockRange" to split multiple requests when the block range is too high.
  • Add more special types for well-known vendors (BlastAPI, Ankr, LlamaRPC, etc) for easier multi-chain support.