Skip to content

Repository files navigation

Open Indexer Benchmark

Discord

An open and honest benchmark for blockchain indexers. Every number below comes from code in this repository, so you can run it yourself and check, and the tables are refreshed automatically by scheduled CI runs.

If you want to know how the numbers are produced, or what a column means, that is all in METHODOLOGY.md.

History

The benchmark started in May 2025 as a fork of Sentio's research. That repository was later closed, so Envio picked it up and has kept it current since. We are not affiliated with Sentio, and although the project now lives under the Envio organisation — its data is what the Envio landing page and the Blockchain Indexers in 2026 article cite — the point of it is a fair comparison.

Contributing

Contributions are welcome — we already have some from the SQD team. Open an issue or a pull request to add an indexer, add a scenario, report a result that looks wrong, or improve the methodology. Indexer teams especially: nobody knows your tool better than you do. Or just come and ask on Discord or Telegram.

Scenarios

Reliability

What does an indexer do when something goes wrong? These scenarios restart its database mid-write, rewrite the chain underneath it, make the node it reads from fail, and hand it values that are legal but awkward, then check what ended up in the database. They also time how long a new block takes to become readable. Every check runs on a generated chain, so no credentials are needed.

tool source crash recovery reorgs rpc faults data fidelity head latency overall
Envio Indexer RPC 11/11 ✅ (2 restarts) 7/7 ✅ 16/16 ✅ 6/6 ✅ 4/4 ✅ (7ms, WS) 44 / 44
Envio Subgraph RPC 11/11 ✅ (2 restarts) 7/7 ✅ 16/16 ✅ 6/6 ✅ 4/4 ✅ (7ms, WS) 44 / 44
Squid SDK RPC 11/11 ✅ (2 restarts) 7/7 ✅ 12/16 🔴 6/6 ✅ 4/4 ✅ (7ms, WS) 40 / 44
Subgraph RPC 9/11 🔴 (no restarts) 7/7 ✅ 13/14 🔴 6/6 ✅ 4/4 ✅ (901ms) 39 / 42
Ponder RPC 8/9 🔴 (no restarts) 7/7 ✅ 14/16 🔴 5/6 🔴 4/4 ✅ (12ms, WS) 38 / 42
SubQuery RPC 11/11 ✅ (no restarts) 0/7 🔴 13/14 🔴 6/6 ✅ 3/4 🔴 (3.8s) 33 / 42
Rindexer RPC 11/11 ✅ (no restarts) 1/7 🔴 8/14 🔴 6/6 ✅ 4/4 ✅ (159ms) 30 / 42
What failed, and what it means for you - 32 failing checks across 5 tools
  • Squid SDK
    • rpc faults
      • Stops indexing: crashes when the RPC node errors or times out
      • Stops indexing: does not resume after the RPC node recovers
      • Stops indexing: crashes when the RPC provider fails some of its requests
      • Stops indexing silently: stops following the chain when its block subscription goes quiet
  • Subgraph
    • crash recovery
      • Stops indexing: never recovers after the database restarts mid-sync (only 1 of 3 runs)
      • Slow deploys: ignores the shutdown signal for over 15 seconds and gets force-killed
    • rpc faults
      • Stops indexing: does not resume after the RPC node recovers
      • not tested: keeps following the chain when its block subscription goes quiet
      • not tested: fills in the blocks it was never told about
  • Ponder
    • crash recovery
      • Stops indexing: never recovers after the database restarts mid-sync
      • not tested: keeps picking up new blocks after the database restarts
      • not tested: recovers by itself when an unresponsive database comes back
    • rpc faults
      • Missing data: deletes rows when an RPC node briefly reports an older block
      • Stops indexing silently: stops following the chain when its block subscription goes quiet
    • data fidelity
      • Missing data: drops events with very large log indexes, which some providers emit
  • SubQuery
    • reorgs
      • Stale data: keeps an event after the chain replaced its block (only 2 of 3 runs)
      • Stale data: keeps blocks from a fork the chain abandoned for a shorter one
      • Stale data: keeps an event the chain removed
      • Wrong data: carries on after a chain rewrite deeper than it can undo, instead of stopping
      • Stale data: misses a chain rewrite that happened while it was offline
      • Wrong data: loses track when the chain rewrites several times in a row
      • Stale data: misses a chain rewrite in blocks it was still syncing
    • rpc faults
      • Wrong balances: counts a transfer twice when the RPC node sends it twice (only 2 of 3 runs)
      • not tested: keeps following the chain when its block subscription goes quiet
      • not tested: fills in the blocks it was never told about
    • head latency
      • Stale reads: new data usually takes longer than one block to show up
  • Rindexer
    • reorgs
      • Stale data: keeps an event after the chain replaced its block
      • Stale data: keeps blocks from a fork the chain abandoned for a shorter one
      • Stale data: keeps an event the chain removed
      • Wrong data: carries on after a chain rewrite deeper than it can undo, instead of stopping
      • Wrong data: loses track when the chain rewrites several times in a row
      • Stale data: misses a chain rewrite in blocks it was still syncing
    • rpc faults
      • Stops indexing: does not resume after the RPC node recovers
      • Stops indexing: never catches up after a spell of flaky RPC
      • Stops indexing: cannot cope with a provider's response-size limit
      • Wrong balances: counts a transfer twice when the RPC node sends it twice
      • Missing data: skips a block the RPC node briefly failed to return
      • Stops indexing: crashes when a block it asked for has just been replaced
      • not tested: keeps following the chain when its block subscription goes quiet
      • not tested: fills in the blocks it was never told about

Each cell is the checks a tool passed out of the checks it was asked. The number in brackets is a measurement beside the score, not part of it.

What every check means, and how to run it →

State Aggregation

How well does an indexer cope with data it has to read back? Every rETH transfer changes a balance, so for each one the indexer has to find the right row, update it, and save it again. The scenario follows the benchmark on the Ponder landing page.

tool source events/s blocks/s vs best data storage
Envio Indexer HyperSync 6,007.9 46,273.3 — ✅ Postgres 2.2 MB
Envio Subgraph HyperSync 5,396.1 43,461.0 1.1x slower ✅ Postgres 2.2 MB
Envio Indexer RPC 2,432.0 19,654.4 2.5x slower ✅ Postgres 2.2 MB
Rindexer HyperSync 982.5 7,927.4 6.1x slower ✅ Postgres 5.2 MB
Squid SDK SQD Network 679.8 5,124.4 8.8x slower ✅ Postgres 2.2 MB
Envio Subgraph RPC 268.3 2,355.1 22.4x slower ✅ Postgres 2.2 MB
Rindexer RPC 229.0 2,047.4 26.2x slower ✅ Postgres 5.0 MB
Ponder RPC 49.6 653.3 121.1x slower ✅ Postgres 3.3 MB
Subgraph RPC 34.7 457.2 173x slower ✅ Postgres 6.9 MB
Substreams StreamingFast 28.7 377.8 209.3x slower ✅ Postgres 2.2 MB
SubQuery RPC 25.2 331.5 238.1x slower ❓ (1) Postgres ~4.4 MB
Squid SDK RPC 16.6 187.3 361.7x slower ❓ (2) Postgres ~2.4 MB

(1) SubQuery — missing 0.22% of the data: the verification range was not finished within 300s (2) Squid SDK — missing 34% of the data: the verification range was not finished within 300s

How this case works, and how to run it →

Decoded Event Stream

How fast can an indexer write? Every USDC transfer is stored once, with nothing to aggregate and nothing to look up first. This is the ingestion path on its own.

tool source events/s blocks/s vs best data storage
Rindexer HyperSync 97,821.2 10,129.6 — ✅ Postgres 3.4 MB
Envio Indexer HyperSync 64,756.2 7,048.5 1.5x slower ✅ Postgres 1.4 MB
Envio Subgraph HyperSync 38,253.0 4,145.7 2.6x slower ✅ Postgres 1.4 MB
Squid SDK SQD Network 15,470.5 1,813.0 6.3x slower ✅ Postgres 1.4 MB
Envio Indexer RPC 12,393.6 1,474.0 7.9x slower ✅ Postgres 1.4 MB
Rindexer RPC 7,447.7 934.9 13.1x slower ✅ Postgres 3.4 MB
Substreams StreamingFast 2,653.1 310.7 36.9x slower ✅ Postgres 1.4 MB
Squid SDK RPC 1,451.3 183.3 67.4x slower ✅ Postgres 1.4 MB
Envio Subgraph RPC 1,306.5 166.2 74.9x slower ✅ Postgres 1.4 MB
Ponder RPC 230.5 29.4 424.3x slower ✅ Postgres 2.5 MB
Subgraph RPC 111.2 13.7 879.8x slower ✅ Postgres 2.8 MB
SubQuery RPC 26.8 3.3 3655.9x slower ❓ (1) Postgres ~2.0 MB

(1) SubQuery — missing 0.36% of the data: the verification range was not finished within 300s

How this case works, and how to run it →

External Contract Calls

Not everything an indexer needs is in the logs. Every approval on the eight busiest ERC-20s is followed by a read of the allowance at that block: 15,703 calls, 200ms each, answered by the benchmark so every tool waits the same. Nothing limits how many a tool may have outstanding, so the rows differ by how many of those waits it takes at once.

tool source events/s blocks/s vs best data storage
Envio Indexer HyperSync 12,715.6 838.4 — ✅ Postgres 8.4 MB
Squid SDK SQD Network 12,374.6 815.8 — ✅ Postgres 8.3 MB
Envio Indexer RPC 11,100.3 728.7 1.1x slower ✅ Postgres 8.2 MB
Rindexer HyperSync 7,728.9 495.5 1.6x slower ✅ Postgres 7.3 MB
Rindexer RPC 7,362.5 473.0 1.7x slower ✅ Postgres 7.3 MB
Envio Subgraph HyperSync 2,149.4 153.3 5.9x slower ✅ Postgres 8.6 MB
Envio Subgraph RPC 1,282.3 79.4 9.9x slower ✅ Postgres 8.6 MB
Squid SDK RPC 838.7 44.4 15.2x slower ✅ Postgres 8.3 MB
Subgraph RPC 71.8 4.5 177.1x slower ✅ Postgres 20.3 MB
Ponder RPC 34.8 2.5 365.7x slower ❓ (1) Postgres ~11.8 MB
SubQuery RPC 4.9 0.3 2611.4x slower ❓ (2) Postgres ~16.6 MB
Substreams StreamingFast — — — — (3) —

(1) Ponder — missing 45% of the data: the verification range was not finished within 300s (2) SubQuery — missing 92% of the data: the verification range was not finished within 300s (3) Substreams — its contract calls run against the Substreams server's own node, not a given endpoint

How this case works, and how to run it →

Factory Contract Registration

What happens when you do not know the contracts up front? The indexer watches the Safe proxy factories, and every one of the 82,268 proxies they create becomes another contract it has to follow from that moment on.

tool source events/s blocks/s vs best data storage
Envio Indexer HyperSync 9,435.5 3,330.9 — ✅ Postgres 14.0 MB
Envio Subgraph HyperSync 8,280.9 2,923.3 1.1x slower ✅ Postgres 14.0 MB
Envio Indexer RPC 6,931.4 2,446.9 1.4x slower ✅ Postgres 14.0 MB
Rindexer HyperSync 6,024.1 2,126.6 1.6x slower ✅ Postgres 11.4 MB
Envio Subgraph RPC 4,075.6 1,438.8 2.3x slower ✅ Postgres 14.0 MB
Squid SDK SQD Network 4,056.7 1,451.3 2.3x slower ❌ (1) Postgres 13.8 MB
Rindexer RPC 3,987.5 1,407.7 2.4x slower ✅ Postgres 11.4 MB
Squid SDK RPC 352.7 124.5 26.7x slower ❌ (2) Postgres 13.8 MB
Substreams StreamingFast 266.7 66.5 35.4x slower ❓ (3) Postgres ~14.5 MB
Ponder RPC 265.9 59.2 35.5x slower ❓ (4) Postgres ~25.4 MB
Subgraph RPC 60.7 27.2 155.4x slower ❓ (5) Postgres ~36.8 MB
SubQuery RPC 0.0 0.0 — ❓ (6) —

(1) Squid SDK — 921 of 927 safe setups missing; 10 of 11 fallback handler changes missing; 211 of 293 module enables missing (2) Squid SDK — 921 of 927 safe setups missing; 10 of 11 fallback handler changes missing; 211 of 293 module enables missing (3) Substreams — missing 5.6% of the data: the verification range was not finished within 300s (4) Ponder — missing 6.1% of the data: the verification range was not finished within 300s (5) Subgraph — missing 79% of the data: the verification range was not finished within 300s (6) SubQuery — indexed nothing in 300s, so there was no data to verify

How this case works, and how to run it →

Solana USDC Transfers

Every USDC transfer on Solana, through the chain's busiest program. Solana makes that harder than it sounds: transfers hide inside swaps and routers, and many never say which token they moved. The scenario follows StreamingFast's SPL token Substreams.

tool source events/s blocks/s vs best data storage
Envio Indexer HyperSync 25,146.8 394.7 — ✅ Postgres 37.8 MB
Squid SDK SQD Network 8,867.8 278.0 2.8x slower ✅ Postgres 37.7 MB
Substreams StreamingFast 3,856.5 126.9 6.5x slower ✅ Postgres 62.7 MB
Carbon RPC 563.2 18.9 44.6x slower ✅ Postgres 40.4 MB

How this case works, and how to run it →

Sentio Benchmark Cases, May 2025

Six scenarios from the original 2025 research, kept here for reference. They are total sync times rather than throughput rates, and they predate the current methodology, so do not compare them with the tables above.

Case Sentio Envio HyperSync Envio HyperIndex Ponder Subsquid Subgraph Sentio_Subgraph Goldsky_Subgraph
case_1_lbtc_event_only 8m 3m 1h40m 10m 3h9m 2h36m
case_2_lbtc_full 6m 1m 45m 34m 1h3m 56m
case_3_ethereum_block 18m 7.9s 33m 1m‡ 10m 15m
case_4_on_transaction 17m 1m26s 33m 7m N/A
case_5_on_trace 16m 41s N/A§ 2m 8m 1h21m
case_6_template 19m 8s 21m 2m 19m 10m 20h24m

More about these cases →

Running the benchmarks

Want to try it yourself? Each scenario page above has its own setup instructions, or you can run the whole suite the way CI does:

ENVIO_API_TOKEN=your-token SQD_API_KEY=your-key node scripts/run-benchmarks.ts

Arguments are passed straight through, so node scripts/run-benchmarks.ts envio ponder --duration=100 picks which indexers to run and how long the window is, and --cases=erc20-transfer-events narrows it to one scenario. You will need an Envio API token for the RPC endpoint and the ground truth; the SQD key is only needed for the Squid SDK run that reads from SQD Network.

About

No description, website, or topics provided.

Resources

Security policy

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages