Choosing a data service

A decision matrix that admits where each option loses, and a default that is right more often than the interesting answer.

7 of 8 in the Developer path intermediate 10 min

Checked against Graph Horizon (2025-12-11)

Last read 2026-08-30 Due again 2026-11-30

Every protocol claim below was read at these sources on 2026-08-30. Where they disagree with each other, the lesson says so.

Four options, honestly compared. Every column loses at least one row, because a comparison that one option wins outright is not a comparison.

The matrix

Token APISubgraphSubstreamsFirehose
Nothing to authoryesnonono
Custom data modelnoyesyesyes
GraphQL API out of the boxnoyesnono
Handles very large backfills wellyesnoyesyes
Output to your own database or warehousenonoyesyes
Multiple chains in one integrationyesnopartlyno
No curation signal needed to be servedyesnon/an/a
Maintainable by a team without Rustyesyesnono
You operate no infrastructureyesyespartlyno

The bolded cells are where each option loses. Note that the subgraph column, the default answer for most people, loses four rows. That is not an argument against it. It is the reason the other services exist.

The decision, in order.

1. Is your question about tokens? Balances, transfers, prices, NFT ownership. If yes, use the Token API and stop. This is the most commonly skipped step and it costs people weeks.

2. Do you need a typed API over one protocol’s state? If yes, write a subgraph. This is the default and it is right most of the time.

3. Is your destination not GraphQL? A warehouse, a stream, your own database. If yes, Substreams with a sink.

4. Is backfill time the binding constraint? History is large, a handler loop takes days, and you cannot wait. Substreams, possibly feeding a subgraph so you keep the GraphQL API.

5. Are you integrating a chain or operating indexing infrastructure? Firehose.

The combination people miss.

Substreams feeding a subgraph. You keep GraphQL for your consumers and change what fills it. When a subgraph is right but its backfill is unworkable, this is usually the answer rather than abandoning the API shape.

Token API plus a subgraph. Almost every application needs both token data and its own protocol state. Using each for its half and joining in your application is straightforward and common.

Costs that are easy to miss.

  • A subgraph needs signal. Publishing does not get it served. That is a real cost and a real delay, covered in the curator path.
  • Substreams needs Rust. Not a snobbery point, a staffing one. A module one person understands is a liability the day that person is on holiday.
  • Firehose is infrastructure. If you are not already operating chain infrastructure, this is a large commitment for a data problem.
  • The Token API’s model is fixed. If your question drifts outside it, you migrate.
Check yourself

Your subgraph is the right shape but backfilling five years of history takes days. Best move?

Which row does the subgraph column lose?

What is the most commonly skipped step in this decision?