The Graph or Subsquid: Indexing Protocols for Web3 Frontends
Your frontend can look complete long before its data layer is ready for production. Token balances render locally, NFT ownership resolves, historical price events line up neatly in a table.

Then users arrive, queries begin to time out, a Subgraph Studio endpoint rate-limits at precisely the wrong moment, and indexing trails the chain while the product team is trying to explain stale numbers.
That is usually when someone opens a document called “hosted subgraphs vs squid sdk” and suddenly the room has strong opinions about blocks-per-second figures nobody has reproduced.
The real question in a the graph vs subsquid indexing performance comparison is not which logo gets to wear the “faster” badge. It is which architecture matches your data model, traffic shape, operational capacity, and appetite for infrastructure. Those are very different questions, and they produce different answers.
Architectural Divergence: Subgraphs vs Batch Extraction
The Graph treats an indexing project as a subgraph: a custom API that watches contracts and events on a chosen network, transforms chain activity through handlers, and stores the result as GraphQL-queryable entities.
The manifest is the centre of gravity. It declares the network, contracts, event sources, mappings, and schema. You write AssemblyScript handlers that react to blockchain events and populate entities. Graph Node takes care of the fetch-process-write loop behind the scenes. The result is a familiar developer experience: define schema, write mappings, deploy, query GraphQL.
Subsquid starts from a different premise. Rather than fitting your application into a subgraph manifest and Graph Node’s storage model, you build a squid: an application using the Subsquid SDK to retrieve blocks in batches, transform the data in code you control, and persist it through a store interface.
That difference changes where the friction lives.
With a subgraph, the operational model is deliberately constrained. You work within Graph Node’s conventions, and that buys you a cleaner route from blockchain events to a public GraphQL API. With a squid, the pipeline is explicit: processor, transformation code, persistence target, query layer. You get more room to shape the system, but you also inherit more of the system.
| Aspect | The Graph subgraph | Subsquid squid |
|---|---|---|
| Core abstraction | Manifest, schema, and AssemblyScript handlers | Processor, store, and custom application code |
| Data pipeline | Fetching, processing, and writing managed inside Graph Node | Explicit batch retrieval, transformation, and persistence |
| Storage layer | Internal Graph Node store | PostgreSQL, filesystem, BigQuery, and other documented targets |
| Query surface | GraphQL through Subgraph Studio or The Graph Network | GraphQL through OpenReader on PostgreSQL, or a custom API |
| Customization boundary | Schema, mappings, entities, and query design | Processor logic, persistence model, schema, and serving layer |
| Decentralized infrastructure | Production decentralized network | Production private cluster; permissionless network described as testnet |
Neither model is inherently more serious. They simply make different promises.
The Graph says: stay inside a standard indexing model and spend your time on the application’s data model. Subsquid says: own the data pipeline, make its assumptions explicit, and tune it for the workload you actually have.
That distinction matters more than it sounds. A frontend team that only needs clean event-derived state does not necessarily benefit from operating PostgreSQL. A protocol analytics team that needs custom joins, warehouse exports, chain-specific filtering, and application-specific aggregation may find Graph Node’s boundaries more constraining than helpful.
Indexing Throughput and the Pipelined Processing Model
The Graph documents indexing as three pipelined stages: fetching relevant chain data from a provider, processing it through mappings, and writing the resulting entities to the store.
When indexing drags, the causes are usually not mysterious. Provider lag can hold the entire process back. Expensive eth_call usage adds RPC pressure. Heavy handlers increase processing time. Large writes and high event volume put pressure on the store. These are ordinary systems problems, but The Graph makes them visible as concrete categories to investigate rather than treating “indexing speed” as one indivisible number.
Subsquid’s model is more overtly batch-shaped. Its SDK extracts ranges of blocks, transforms the relevant data, and persists results through a separate store. This is especially suited to historical indexing, where the work can be organized around ranges and parallelizable units rather than a single event-by-event stream.
That architectural separation is the basis for the high throughput figures Subsquid publishes.
Raw block throughput is not frontend performance. A fast historical sync can still sit behind a poorly indexed database or an expensive GraphQL query.
Subsquid’s own comparison material reports roughly 1,000–50,000 blocks per second for Subsquid Network plus Squid SDK, compared with roughly 100–150 blocks per second for The Graph. Those numbers are useful as an indication of how Subsquid frames its advantage. They are not a substitute for a benchmark.
The missing context is the part teams should care about: chain, block range, event filters, data volume, transformation complexity, entity or table design, RPC provider, hardware, store configuration, software version, and whether the indexer is syncing history or tracking a live chain tip. Without that context, “faster” has very little engineering meaning.
A transfer-only indexer on a quiet chain is not comparable to a protocol indexer that makes calls, maintains relationship-heavy entities, calculates derived state, and serves a public GraphQL endpoint under load. Nor is historical catch-up comparable to real-time indexing after deployment.
For a credible the graph vs subsquid indexing performance comparison, run the same workload through both systems:
1. Use the same network, block range, contract set, and event filters.
2. Reproduce the same transformation requirements rather than comparing a thin extraction job to a rich application schema.
3. Measure historical synchronization separately from live indexing lag.
4. Test query latency against representative frontend queries after the dataset is fully indexed.
5. Include operational work in the decision: database tuning, endpoint management, retries, monitoring, and recovery after a failure.
The uncomfortable truth is that a number from a comparison page is often less valuable than a modest benchmark built around the exact query your product needs to answer.
Optimization Patterns for Subgraph Schema Performance
The Graph is not a sealed appliance where your only choice is to accept whatever performance arrives with the deployment. Schema design has a direct effect on both indexing and query work.
The Graph’s documentation reports that immutable entities, combined with Bytes IDs for join keys, produced up to a 48% increase in indexing speed and up to a 28% increase in query performance in its tests.
The mechanism matters here. An immutable entity is declared as something that will not change after creation. Because it never needs to be updated, Graph Node can avoid the update path and avoid live-version filtering for that entity. Fixed-width Bytes IDs can also reduce the cost of joins compared with more cumbersome identifier shapes.
That does not make immutable entities a decorative optimization flag. It is a data-model decision.
If the application is indexing an append-only history—transfers, mints, votes, claims, oracle observations, liquidation events, settlement records—then the data is often genuinely immutable. Model it that way from the beginning. Do not create a mutable entity merely because it is convenient to put every field in one place.
A useful pattern is to split stable historical records from mutable summary state:
- Keep each transfer, mint, vote, or trade as an immutable entity.
- Maintain a smaller mutable entity only for current state that must actually change, such as a user balance snapshot or a protocol-wide aggregate.
- Use IDs that reflect the event’s natural uniqueness, commonly a transaction-and-log-position combination where appropriate.
- Avoid repeated contract calls in handlers when the same information can be derived from the event stream or stored once.
- Design relationship-heavy queries around the way the frontend reads data, not around the way the contracts happen to be organized.
Immutable entities are not “more aggressively filtered.” They avoid updates and live-version filtering altogether, which is precisely why they can be cheaper to index.
The broader lesson is that schema performance is product design in disguise. A subgraph schema that treats every event as a mutable object creates work the application never asked for. A schema that mirrors the frontend’s access patterns gives GraphQL fewer reasons to wander across large entity sets.
| Optimization target | The Graph | Subsquid |
|---|---|---|
| Schema and entity design | Immutable entities and Bytes IDs are documented performance levers | Full control over database schema and application model |
| Provider layer | Provider lag and RPC load are known indexing bottlenecks | Archival data services or external EVM RPC endpoints, depending on setup |
| Database tuning | Managed internally by Graph Node, with less direct control | Direct PostgreSQL configuration, indexes, partitions, and connection management |
| Query surface | GraphQL with Graph Node caching and schema-level choices | OpenReader GraphQL or a fully custom serving layer |
| Indexing parallelism | Internal pipeline management | Batch-oriented processing that can be parallelized across ranges |
Subsquid moves many of these decisions into territory that database-minded teams will recognize immediately. You choose indexes. You choose partitions. You decide what becomes a table, what becomes a materialized representation, what gets precomputed, and how the GraphQL layer maps to the store.
That flexibility is powerful, but it is not free. It replaces Graph Node’s opinionated constraints with operational responsibility.
Data Persistence and Flexible Store Targets for Frontends
For a frontend team, the question eventually becomes embarrassingly simple: where do the queries go, and who owns the thing answering them?
With The Graph, the production route is a GraphQL endpoint through The Graph Network, accessed with an API key. Subgraph Studio is intended for testing and is rate-limited, which makes it useful during development but not a substitute for a production access plan. The Graph’s Free Plan documents 100,000 queries per month. That can be entirely adequate for early validation, but it becomes a real capacity assumption as soon as the product has regular traffic.
Plan around that before launch week. A dashboard that becomes popular because it is useful has a way of turning an innocent query budget into a product incident.
Subsquid’s model gives you a different kind of ownership. A squid backed by PostgreSQL can expose GraphQL through OpenReader, with optional custom queries and basic access control. The frontend still talks GraphQL. React does not care whether the response came from Graph Node or a Postgres-backed OpenReader service. But your team cares, because the database is now part of your application infrastructure.
That means backups, migrations, indexes, connection pools, access controls, observability, recovery procedures, and capacity planning belong to you.
For teams already operating services and databases, this may be exactly the point. A custom pipeline can serve both the product and internal analytics. Subsquid’s documented BigQuery target is particularly relevant when indexing is not just a frontend concern but part of a wider data operation: product metrics, wallet segmentation, risk monitoring, protocol research, or business intelligence.
The Graph’s internal store is optimized around serving the subgraph. It is not positioned as a warehouse feed. If your organization needs both frontend queries and a broader analytics destination, you will normally build that export or parallel pipeline separately.
This is where querying blockchain data with graphql can look deceptively uniform from the browser while being radically different behind the endpoint.
A GraphQL query is only the final request. Its real cost is determined upstream by the data model:
- How many entities does the query fan out across?
- Are relationships modeled for the access path the UI needs?
- Is the endpoint public, rate-limited, gateway-backed, or privately operated?
- Can the backing store sustain simultaneous dashboard traffic and indexer writes?
- Does the query depend on live chain state, or can it tolerate indexed data lag?
We have seen teams write an entirely reasonable GraphQL query and then discover that the underlying relationship was effectively asking the system to sift through thousands of rows every time a user opened a profile page. The syntax was innocent. The model underneath it was not.
Network Maturity and Decentralized Infrastructure Status
The Graph’s decentralized network is a production system. Indexers, delegation, curation, query fees, and the API-key-based gateway are not theoretical parts of a roadmap; they are established pieces of the platform’s operating model.
Deploying to The Graph Network means publishing into infrastructure that other participants can run and serve. That maturity shows up in tooling, documentation, deployment patterns, and the ecosystem built around public subgraphs.
Subsquid’s documentation describes two deployments with a similar user-facing API but very different infrastructure implications.
One is a production-ready private cluster operated on Subsquid infrastructure. The other is a decentralized, permissionless network that is still described as a testnet. That distinction should not be blurred by marketing language or by the fact that both routes can feel similar from the application layer.
A team choosing Subsquid for production today is choosing the SDK and the production private cluster, not a fully mature permissionless indexing network.
Decentralization at the indexing layer is not a mood board. The Graph is further along operationally; Subsquid’s permissionless deployment is still experimental by its own documentation.
That is not an indictment of Subsquid. It is simply the actual shape of the decentralized data indexing trade-offs.
If your product’s thesis includes minimizing dependence on a single infrastructure operator, The Graph has a stronger present-day story. If decentralization of the indexing layer is not central to the product, then Subsquid’s private cluster and flexible SDK model may be more useful than a more decentralized but more constrained route.
The question becomes sharper when looking at L2s. The issue in subsquid vs the graph for l2 networks is not merely whether each tool supports the chain you want. It is whether the combination of chain data availability, provider quality, indexing lag, deployment maturity, and query infrastructure matches the user experience you are promising.
L2 applications often create their own pressure profile: transaction volume can be high, event patterns can be dense, and users can be especially sensitive to freshness because the product feels fast everywhere else. A dashboard that waits for indexing while the chain confirms quickly feels broken, even if the underlying protocol is behaving normally.
What We’d Actually Pick, When
For an event-heavy application where the team is primarily frontend-oriented and does not want to operate PostgreSQL, a subgraph is usually the sensible first move. The development path is mature, GraphQL is native to the model, and the progression from local work to a public endpoint is easier to explain to the rest of the company.
In that case, the important work is not avoiding The Graph because a vendor comparison says another system processes more blocks per second. The important work is designing entities properly from day one: immutable records where history does not change, carefully chosen IDs, restrained handler logic, and queries shaped around real screens rather than hypothetical data exploration.
For historical workloads with high event volume, filtered extraction, custom transformations, or a clear need to own the persistence layer, Subsquid is compelling. If the team already knows how to run Postgres and wants direct control over schema design, analytics exports, and API behavior, the Squid SDK can be a much more natural fit than adapting the product to a subgraph’s model.
For a frontend that depends on permissionless indexing infrastructure in production, we would not treat Subsquid’s decentralized network as the default choice while its own documentation labels it a testnet. The private cluster may be production-ready. That is a different claim, and it should be evaluated as such.
The Graph or Subsquid is not a referendum on whether managed conventions are good or whether custom infrastructure is virtuous. It is a decision about where your team wants complexity to live.
The Graph asks you to be disciplined about entities, mappings, and GraphQL access patterns. Subsquid asks you to be disciplined about the entire data pipeline, including the database and serving layer. Both can produce fast, reliable frontend data. Both can also become slow, expensive, and hard to reason about when the architecture is chosen for a benchmark number rather than for the workload in front of you.
That is the answer worth carrying into the planning meeting: pick the indexing system whose trade-offs your team can actually operate after the first impressive throughput chart has been forgotten.