Skip to content
On this page

Fallback Transport โ€‹

The fallback Transport consumes multiple Transports. If a Transport request fails, it will fall back to the next one in the list.

Import โ€‹

ts
import { fallback } from 'viem'

Usage โ€‹

ts
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'

const alchemy = http({ 
  url: 'https://eth-mainnet.g.alchemy.com/v2/...' 
})
const infura = http({ 
  url: 'https://mainnet.infura.io/v3/...' 
})

const client = createPublicClient({
  chain: mainnet,
  transport: fallback([alchemy, infura]),
})

Transport Ranking โ€‹

Transport Ranking enables each of the Transports passed to the fallback Transport are automatically ranked based on their latency & stability via a weighted moving score algorithm.

Every 10 seconds (interval), the fallback Transport will ping each transport in the list. For the past 10 pings (sampleCount), they will be ranked based on if they responded (stability) and how fast they responded (latency). The algorithm applies a weight of 0.7 to the stability score, and a weight of 0.3 to the latency score to derive the final score which it is ranked on.

The Transport that has the best latency & stability score over the sample period is prioritized first.

You can turn on automated ranking with the rank option:

ts
const client = createPublicClient({
  chain: mainnet,
  transport: fallback(
    [alchemy, infura],
    { rank: true } 
  ),
})

You can also modify the default rank config:

ts
const client = createPublicClient({
  chain: mainnet,
  transport: fallback(
    [alchemy, infura],
    { 
      rank: {
        interval: 60_000,
        sampleCount: 5,
        timeout: 500,
        weights: {
          latency: 0.3,
          stability: 0.7
        }
      }
    }
  ),
})

Parameters โ€‹

rank (optional) โ€‹

  • Type: boolean | RankOptions
  • Default: true

Whether or not to automatically rank the Transports based on their latency & stability. Set to false to disable automatic ranking.

ts
const transport = fallback([alchemy, infura], {
  rank: false, 
})

rank.interval (optional) โ€‹

  • Type: number
  • Default: client.pollingInterval

The polling interval (in ms) at which the ranker should ping the RPC URL.

ts
const transport = fallback([alchemy, infura], {
  rank: { 
    interval: 5_000
  },
})

rank.sampleCount (optional) โ€‹

  • Type: number
  • Default: 10

The number of previous samples to perform ranking on.

ts
const transport = fallback([alchemy, infura], {
  rank: { 
    sampleCount: 10
  },
})

rank.timeout (optional) โ€‹

  • Type: number
  • Default: 1_000

Timeout when sampling transports.

ts
const transport = fallback([alchemy, infura], {
  rank: { 
    timeout: 500
  },
})

rank.weights.latency (optional) โ€‹

  • Type: number
  • Default: 0.3

The weight to apply to the latency score. The weight is proportional to the other values in the weights object.

ts
const transport = fallback([alchemy, infura], {
  rank: {
    weights: {
      latency: 0.4, 
      stability: 0.6
    }
  },
})

rank.weights.stability (optional) โ€‹

  • Type: number
  • Default: 0.7

The weight to apply to the stability score. The weight is proportional to the other values in the weights object.

ts
const transport = fallback([alchemy, infura], {
  rank: {
    weights: {
      latency: 0.4,
      stability: 0.6 
    }
  },
})

retryCount (optional) โ€‹

  • Type: number
  • Default: 3

The max number of times to retry when a request fails.

Note: The fallback will first try all the Transports before retrying.

ts
const transport = fallback([alchemy, infura], {
  retryCount: 5, 
})

retryDelay (optional) โ€‹

  • Type: number
  • Default: 150

The base delay (in ms) between retries. By default, the Transport will use exponential backoff (~~(1 << count) * retryDelay), which means the time between retries is not constant.

ts
const transport = fallback([alchemy, infura], {
  retryDelay: 100, 
})

Released under the MIT License.