Logo
New RPC users get 35% off their first monthView the offer
OnFinality Learn
Infrastructure & Operations11 min read

Chainstack vs QuickNode: A Reproducible Method for Choosing an RPC Provider

A workload-first framework for comparing Chainstack and QuickNode on metering, latency, archive depth, and failover, with runnable probes you can repeat on your own traffic.

TL;DR

Chainstack and QuickNode are both managed multi-chain RPC platforms, so the decision rarely turns on a single headline number. The meaningful differences show up in how each meters requests, what your specific method mix costs, how latency behaves at p95 and p99 in your region, and whether archive, trace, and WebSocket workloads are covered by your plan. This article gives you a repeatable procedure: model your workload, probe both endpoints with identical scripts, verify archive and debug behavior, test failover, and only then compare invoices. Run the measurements yourself against your own contracts and regions; the numbers below are placeholders until you fill them in.

What a Chainstack vs QuickNode decision actually tests

Both providers expose JSON-RPC over HTTPS and WebSocket across a broad set of EVM and non-EVM networks, and both offer shared and dedicated node tiers. That overlap means a feature checklist will usually end in a tie. The decision is better framed as a workload-fit question: which provider's metering model, regional footprint, and plan limits match the traffic your application actually generates?

This article is a measurement methodology, not a verdict. It assumes you already have a candidate network, a representative set of RPC methods, and at least one staging environment where you can point a client at two endpoints. If you only need a concrete endpoint recommendation for a specific chain, the RPC Assistant endpoint guides are the faster path; come back here when you need to justify a provider choice to a team.

  • Scope: EVM JSON-RPC plus WebSocket subscriptions, with notes on archive and trace methods.
  • Out of scope: negotiated enterprise contracts, legal terms, and provider-side incident history.
  • Assumption: you can run scripts from the same machine and region you deploy from.

Prerequisites and a clean test harness

Before comparing anything, freeze the variables. Use one client machine per region, the same HTTP library, the same timeout, and the same payloads for both providers. Record the plan tier for each endpoint, because a free tier and a paid tier are not comparable and will produce misleading latency and rate-limit results.

Create two environment variables, one per provider, and never hardcode keys in scripts. Keep a third variable for a fallback endpoint so you can test failover later. Store raw results as JSON so you can recompute percentiles without rerunning the test.

  • Pin the client version and OS so latency deltas are not library artifacts.
  • Run each probe at the same time of day across at least three separate windows.
  • Log the HTTP status code alongside latency; a fast 429 is not a fast success.
export CHAINSTACK_RPC_URL="https://your-chainstack-endpoint"
export QUICKNODE_RPC_URL="https://your-quicknode-endpoint"
export FALLBACK_RPC_URL="https://your-secondary-endpoint"
export TEST_ADDRESS="0x0000000000000000000000000000000000000000"

The metering mental model: credits, request units, and method weight

The largest source of bill shock in any RPC comparison is method weighting. Providers that meter with credits or request units often assign different weights to different JSON-RPC methods: a simple block number lookup may cost one unit, while eth_getLogs over a wide range or a debug_traceCall may cost many. A plan that looks cheaper at a headline quota can invert once your real method mix is applied.

The practical approach is to build a method-mix table from your own logs. For each method you call, record the call count over a representative period and the provider's published weight for that method. Multiply and sum to get weighted units per period, then compare that figure against each plan's included quota and overage rate. Do this before you run any latency test, because the cheaper endpoint at low volume may be the wrong one at production volume.

Documented behavior differs by plan and can change, so treat any weight you read as a snapshot with a date. Re-check weights whenever you change your application's call pattern, especially if you add indexing, tracing, or log-heavy analytics.

  • Count calls per method, not total calls; averages hide expensive outliers.
  • Separate read-heavy methods (eth_call, eth_getLogs) from trace and debug methods.
  • Model a 2x and 5x growth scenario to see where overage rates start to dominate.

Building a workload profile from your own traffic

If you already run in production, export a week of RPC method counts from your gateway or client logs. If you are pre-launch, estimate from your application's read paths: how often each page or job calls balance, logs, receipts, and traces. The goal is a small table you can reuse for both providers.

The script below summarizes a JSON file of method counts into a weighted total given a per-method weight map. Replace the weight map with the values published for each provider plan you are evaluating, and keep the two outputs side by side.

  • Run the same counts through both providers' weight maps.
  • Flag any method whose weight you could not confirm from documentation.
  • Keep the raw counts file under version control so comparisons are auditable.
import json, sys

# method_counts.json: {"eth_call": 120000, "eth_getLogs": 4000, ...}
with open("method_counts.json") as f:
    counts = json.load(f)

# Replace with weights published for the plan you are evaluating.
weights = {
    "eth_call": 1,
    "eth_getLogs": 10,
    "eth_getBlockByNumber": 1,
    "debug_traceCall": 50,
}

total = 0
for method, n in counts.items():
    w = weights.get(method, 1)
    total += n * w
    print(f"{method:28s} calls={n:>10d} weight={w:>3d} units={n*w:>12d}")
print(f"TOTAL WEIGHTED UNITS: {total}")

Latency and reliability probes you can repeat

Latency comparisons are only meaningful when the payload, region, and concurrency match. Start with a sequential probe to establish a baseline, then add concurrency to see how each endpoint behaves under load. Measure p50, p95, and p99 rather than the mean, because tail latency is what users feel during congestion.

The Python script below issues the same eth_blockNumber call repeatedly against both endpoints, records status codes and durations, and prints percentiles. Run it from the region your users are in, and repeat for a heavier method such as eth_getLogs with a realistic block range.

  • Run at least three windows per provider and compare distributions, not single runs.
  • Record failures separately; a 429 during a burst is a capacity signal.
  • Repeat from a second region if your users are geographically distributed.
import os, time, json, statistics, urllib.request

def probe(url, method="eth_blockNumber", params=None, n=200):
    payload = json.dumps({"jsonrpc":"2.0","id":1,"method":method,"params":params or []}).encode()
    results = []
    for _ in range(n):
        req = urllib.request.Request(url, data=payload, headers={"Content-Type":"application/json"})
        start = time.perf_counter()
        try:
            with urllib.request.urlopen(req, timeout=10) as r:
                r.read()
                status = r.status
        except Exception as e:
            status = getattr(e, "code", "error")
        results.append((status, (time.perf_counter() - start) * 1000))
    ok = [ms for s, ms in results if s == 200]
    ok.sort()
    def pct(p):
        return ok[min(len(ok)-1, int(len(ok)*p))] if ok else None
    return {"success": len(ok), "total": n, "p50": pct(0.50), "p95": pct(0.95), "p99": pct(0.99)}

for name in ["CHAINSTACK_RPC_URL", "QUICKNODE_RPC_URL"]:
    print(name, probe(os.environ[name]))

Recording results in a comparison table

Capture every run in a table so the decision is auditable and reproducible. The table below is a template; fill it with your own measured values rather than relying on any published benchmark. Keep the plan tier and test date in the same row, because both change over time.

ProviderPlan tierRegionMethodSuccess / totalp50 (ms)p95 (ms)p99 (ms)Notes
Chainstack(your tier)(your region)eth_blockNumber(fill)(fill)(fill)(fill)(fill)
QuickNode(your tier)(your region)eth_blockNumber(fill)(fill)(fill)(fill)(fill)
Chainstack(your tier)(your region)eth_getLogs(fill)(fill)(fill)(fill)(fill)
QuickNode(your tier)(your region)eth_getLogs(fill)(fill)(fill)(fill)(fill)

Treat any row with a success rate below your threshold as a failed candidate regardless of latency. A provider that returns fast errors is not faster than one that returns correct data slightly later.

Verifying archive depth, trace support, and WebSocket behavior

Archive and debug access are the features most likely to differ between plan tiers, and they are the easiest to verify with a single call. Query a historical block well outside the recent window and confirm the response contains state rather than a pruned-data error. Then attempt a trace or debug method and record whether it succeeds, returns an unsupported-method error, or is rate-limited.

For WebSocket, subscribe to new heads and measure the gap between the block timestamp and the time your client receives the notification. Disconnect and reconnect deliberately to see how each endpoint handles resubscription. If your application depends on real-time data, this test matters more than HTTP latency.

  • A pruned-state error on a historical block means archive access is not included in that tier.
  • An unsupported-method error on debug_traceCall is a capability gap, not a latency issue.
  • For WebSocket, log reconnect time and whether subscriptions resume automatically.
curl -s -X POST "$CHAINSTACK_RPC_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["'"$TEST_ADDRESS"'","0x1"]}'

curl -s -X POST "$QUICKNODE_RPC_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"debug_traceCall","params":[{"to":"'"$TEST_ADDRESS"'","data":"0x"},"latest",{}]}'

Failover and rate-limit behavior under burst

Production reliability depends less on steady-state latency than on what happens when you exceed a limit. Send a short burst above your expected peak and observe the response: a 429 with a Retry-After header is recoverable, while a silent timeout or connection reset is harder to handle. Then test your client's failover path by pointing it at a primary and fallback endpoint and forcing the primary to fail.

A simple pattern is a round-robin or priority list of endpoints with a health check. The configuration below shows a priority list with a timeout and one retry, which you can adapt to your client library. Keep the fallback on a different provider so a single provider incident does not take down both paths.

  • Log which provider served each request so you can attribute incidents.
  • Set a timeout shorter than your user-facing SLA budget.
  • Test failover during a real burst, not only in steady state.
const endpoints = [
  { name: "primary", url: process.env.CHAINSTACK_RPC_URL },
  { name: "secondary", url: process.env.QUICKNODE_RPC_URL },
  { name: "fallback", url: process.env.FALLBACK_RPC_URL },
];

async function rpc(method, params) {
  for (const ep of endpoints) {
    try {
      const res = await fetch(ep.url, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
        signal: AbortSignal.timeout(3000),
      });
      if (!res.ok) continue;
      const body = await res.json();
      if (body.error) continue;
      return { provider: ep.name, result: body.result };
    } catch (e) {
      // try next endpoint
    }
  }
  throw new Error("all endpoints failed");
}

Translating measurements into a cost and risk decision

Once you have weighted units, latency percentiles, capability results, and failover behavior, combine them into a decision matrix. Weight each dimension by how much it matters to your application: a trading bot may weight p99 latency heavily, while an analytics indexer may weight log-query cost and archive depth. Multiply your weighted units by each plan's overage rate to estimate monthly cost at your current and projected volume.

Do not collapse the decision into a single score without recording the inputs. When a provider changes pricing or you change your method mix, you want to rerun the model rather than redo the research. For teams standardizing on one platform across many chains, the multi-chain endpoint guide and the network directory help confirm chain coverage before you commit.

  • Cost = included quota cost + (weighted units beyond quota × overage rate).
  • Risk = incident exposure × failover quality × capability gaps.
  • Re-run the model quarterly or whenever your method mix changes materially.

Troubleshooting common comparison mistakes

Most bad provider comparisons come from mismatched conditions rather than real performance differences. The list below covers the failures we see most often when teams benchmark RPC endpoints.

If a probe returns errors on one provider but not the other, check the plan tier and method support before concluding a performance gap. If latency looks implausibly low, confirm the response actually contained data and was not a cached or error response. If WebSocket tests are flaky, verify your client handles ping/pong and resubscription, since some libraries silently drop subscriptions after a reconnect.

  • Comparing a free tier against a paid tier.
  • Testing from a laptop on a different network than production.
  • Ignoring method weights when comparing headline quotas.
  • Measuring only the mean and missing tail latency.
  • Assuming archive or trace access is included without testing it.
  • Failing over to a second endpoint on the same provider.

Limitations and next steps

This method measures what you can observe from your own client: latency, success rate, capability, and modeled cost. It cannot capture provider-side incident history, support responsiveness, or contractual terms, which you should evaluate separately. Published weights and plan limits change, so any comparison has a shelf life; date your results and revisit them.

A practical next step is to run the probe scripts against your staging workload for one week, fill the comparison table, and review the result with the team that owns the application. If you need dedicated capacity or predictable throughput for a specific chain, review the dedicated node options and the RPC pricing structure alongside your measured units. For teams that want a managed endpoint without running the comparison themselves, the API service overview describes how endpoints are provisioned and scaled.

  • Run the workload profile and latency probes for at least one week.
  • Fill the comparison table with measured values and a test date.
  • Re-check method weights and plan limits before signing a contract.
  • Keep a cross-provider fallback in production regardless of the winner.

Never Worry about Infrastructure Again

OnFinality takes away the heavy lifting of DevOps so you can build smarter and faster.

Get Started