Config
Networks

Networks

A network represents a chain (e.g., evm, solana, etc), and it is a logical grouping of upstreams.

Upstreams are configured separately, and on the first request to a network, the eRPC will automatically find any upstream that support that network.

You can configure failover behavior per network as follows:

erpc.yaml
projects:
  - id: main
 
    # (OPTIONAL) This array configures network-specific (a.k.a chain-specific) features.
    # For each network "architecture" and corresponding network id (e.g. evm.chainId) is required.
    # You don't need to define networks as they will be automatically detected from configured endpoints (lazy-loaded).
    # Only provide network list if you want to customize features such as failsafe policies, rate limit budget, finality depth, etc.
    networks:
      - architecture: evm
        # (OPTIONAL) When "evm" is used, "chainId" is required, so that rate limit budget or failsafe policies are properly applied.
        evm:
          # (REQUIRED) chainId is required when "evm" architecture is used.
          chainId: 1
          # (OPTIONAL) fallbackFinalityDepth is optional and allows to manually set a finality depth in case upstream does not support eth_getBlockByNumber(finalized).
          # In case this fallback is used, finalized block will be 'LatestBlock - fallbackFinalityDepth'.
          # Defining this fallback helps with increasing cache-hit rate and reducing redundant 'retry' attempts on empty responses, as we know which data is finalized.
          # DEFAULT: auto-detect - via eth_getBlockByNumber(finalized).
          fallbackFinalityDepth: 1024
 
        # (OPTIONAL) Refer to "Selection Policy" section for more details.
        # Here are default values used for selectionPolicy if not explicitly defined:
        selectionPolicy:
          # Every 1 minute evaluate which upstreams must be included,
          # based on the arbitrary logic (e.g., <90% error rate and <10 block lag):
          evalInterval: 1m
          
          # To isolate selection evaluation and result to each "method" separately change this flag to true
          evalPerMethod: false
          
          # Freeform TypeScript-based logic to select upstreams to be included by returning them:
          evalFunction: |
            (upstreams, method) => {
              
              const defaults = upstreams.filter(u => u.config.group !== 'fallback')
              const fallbacks = upstreams.filter(u => u.config.group === 'fallback')
              
              // Maximum allowed error rate.
              const maxErrorRate = parseFloat(process.env.ROUTING_POLICY_MAX_ERROR_RATE || '0.7')
              
              // Maximum allowed block head lag.
              const maxBlockHeadLag = parseFloat(process.env.ROUTING_POLICY_MAX_BLOCK_HEAD_LAG || '10')
              
              // Minimum number of healthy upstreams that must be included in default group.
              const minHealthyThreshold = parseInt(process.env.ROUTING_POLICY_MIN_HEALTHY_THRESHOLD || '1')
              
              // Filter upstreams that are healthy based on error rate and block head lag.
              const healthyOnes = defaults.filter(
                u => u.metrics.errorRate < maxErrorRate && u.metrics.blockHeadLag < maxBlockHeadLag
              )
              
              // If there are enough healthy upstreams, return them.
              if (healthyOnes.length >= minHealthyThreshold) {
                return healthyOnes
              }
 
 
              // If there are fallbacks defined, try to use them
              if (fallbacks.length > 0) {
                // Apply same health filtering as default rpcs
                let healthyFallbacks = fallbacks.filter(
                  u => u.metrics.errorRate < maxErrorRate && u.metrics.blockHeadLag < maxBlockHeadLag
                )
 
                // If there are healthy fallbacks use them
                if (healthyFallbacks.length > 0) {
                  return healthyFallbacks
                }
              }
 
              // The reason all upstreams are returned is to be less harsh and still consider default nodes (in case they have intermittent issues)
              // Order of upstreams does not matter as that will be decided by the upstream scoring mechanism
              return upstreams
            }
          
          # When an upstream is excluded, you can give it a chance on a regular basis
          # to handle a certain number of sample requests again, so that metrics are refreshed.
          # For example, to see if error rate is improving after 5 minutes, or still too high.
          # This is conceptually similar to how a circuit-breaker works in a "half-open" state.
          # Resampling is not always needed because the "evm state poller" component will still make
          # requests for the "latest" block, which still updates errorRate.
          resampleExcluded: false
          resampleInterval: 5m
          resampleCount: 10
 
        # (OPTIONAL) A network-level rate limit budget applied to all requests despite upstreams own rate-limits.
        # For example even if upstreams can handle 1000 RPS, and network-level is limited to 100 RPS,
        # the request will be rate-limited to 100 RPS.
        rateLimitBudget: my-limiter-budget
 
        # (OPTIONAL) Refer to "Failsafe" section for more details.
        # Here are default values used for networks if not explicitly defined:
        failsafe:
          timeout:
            # On network-level "timeout" is applied for the whole lifecycle of the request (including however many retries happens on upstream)
            duration: 30s
          retry:
            # It is recommended to set a retry policy on network-level to make sure if one upstream is rate-limited,
            # the request will be retried on another upstream.
            maxAttempts: 3
            delay: 100ms
            jitter: 0ms
            backoffMaxDelay: 1s
            backoffFactor: 1.5
          # Defining a "hedge" is highly-recommended on network-level because if upstream A is being slow for
          # a specific request, it can start a new parallel hedged request to upstream B, for whichever responds faster.
          hedge:
            delay: 200ms
            maxCount: 3
    
    upstreams:
    # Refer to "Upstreams" section to learn how to configure upstreams.
    # ...
# ...

Default config and lazy-loading

Networks are lazy-loaded on first request for a network (if not explicitly defined in config). You can configure "networkDefaults" to set default values for all networks (both static or lazy-loaded):

erpc.yaml
projects:
  - id: main
    networkDefaults:
      # (OPTIONAL) A network-level rate limit budget applied to all requests despite upstreams own rate-limits.
      # For example even if upstreams can handle 1000 RPS, and network-level is limited to 100 RPS,
      # the request will be rate-limited to 100 RPS.
      # Defaults to no rate limit budget.
      rateLimitBudget: "my-default-budget"
 
      # (OPTIONAL) Refer to "Failsafe" section for more details.
      # https://docs.erpc.cloud/config/failsafe
      # If a network has its own failsafe defined, it will not take any of policies from networkDefaults.
      # i.e. if network has only "timeout" policy, it will NOT get hedge/retry from networkDefaults (those will be disabled).
      # Here are default values used for networkDefaults if not explicitly defined:
      failsafe:
        timeout:
          duration: "30s"
        hedge:
          delay: "200ms"
          maxCount: 3
        retry:
          maxAttempts: 3
          delay: "100ms"
          jitter: "0ms"
          backoffMaxDelay: "1s"
          backoffFactor: 1.5
 
      # (OPTIONAL) Refer to "Selection Policy" section for more details about default values.
      # https://docs.erpc.cloud/config/projects/selection-policies#config
      selectionPolicy:
        #...
 
      # (OPTIONAL) Default directives to apply to all requests for this network.
      # These can be overridden by request-specific directives via HTTP headers or query parameters.
      # See https://docs.erpc.cloud/operation/directives for more details about each directive.
      directiveDefaults:
        retryEmpty: true                       # OPTIONAL (default: true)
        retryPending: false                    # OPTIONAL (default: false)
        skipCacheRead: false                   # OPTIONAL (default: false)
        useUpstream: "alchemy-*|localnode-*"   # OPTIONAL (default: *)
    
    # (OPTIONAL) List of customizations per network if needed can be defined as usual:
    # For each static network, first networkDefaults will be applied (deep object merge),
    # then network-specific overrides can be applied.
    networks:
      # ...

If a network has its own failsafe: defined, it will not take any of policies from networkDefaults.
e.g. if a network only has "timeout" policy, it will NOT get hedge/retry from networkDefaults (those will be disabled).

Architectures

evm

This type of network are generic EVM-based chains that support JSON-RPC protocol.

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:


  • Add support for more architectures (Solana, etc)