Solana RPC guide

RPC Batching and Retries

Reduce RPC calls and retry temporary failures without duplicate work.

Batch independent reads. Retry only temporary failures.

Send a batch

A JSON-RPC batch is an array of request objects. Give each request a unique ID.

const requests = [  {    jsonrpc: "2.0",    id: "slot",    method: "getSlot",    params: [{ commitment: "confirmed" }],  },  {    jsonrpc: "2.0",    id: "health",    method: "getHealth",  },  {    jsonrpc: "2.0",    id: "epoch",    method: "getEpochInfo",    params: [{ commitment: "confirmed" }],  },] const response = await fetch("https://rpc.nln.clr3.org", {  method: "POST",  headers: {    "content-type": "application/json",    "x-api-key": process.env.NLN_API_KEY,  },  body: JSON.stringify(requests),}) const results = await response.json()const byId = Object.fromEntries(results.map((item) => [item.id, item]))console.log(byId.slot.result)

Response order does not need to match request order. Match each result by ID.

Pick retryable failures

Retry these responses:

  • HTTP 429
  • HTTP 500
  • HTTP 502
  • HTTP 503
  • HTTP 504
  • Network timeout
  • Connection reset before a response

Do not retry these responses without changing the request:

  • HTTP 400
  • HTTP 401
  • JSON-RPC -32601
  • JSON-RPC -32602

Use bounded backoff

const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) async function rpc(body, attempt = 0) {  const response = await fetch("https://rpc.nln.clr3.org", {    method: "POST",    headers: {      "content-type": "application/json",      "x-api-key": process.env.NLN_API_KEY,    },    body: JSON.stringify(body),    signal: AbortSignal.timeout(10_000),  })   if ([429, 500, 502, 503, 504].includes(response.status) && attempt < 4) {    const base = 250 * 2 ** attempt    const jitter = Math.floor(Math.random() * 150)    await wait(base + jitter)    return rpc(body, attempt + 1)  }   const result = await response.json()  if (!response.ok || result.error) {    throw new Error(result.error?.message ?? `HTTP ${response.status}`)  }  return result.result}

Protect transaction submission

Treat sendTransaction differently from reads.

  • Keep the same signed transaction across retries.
  • Query the signature before a second submission.
  • Stop after the blockhash expires.
  • Do not build a new transaction inside the retry loop.