Docs

9 Time & Money Saving Subgraph Optimizations

Slow-loading data, delayed queries, or performance hiccups can frustrate even the most loyal users and drive them away.

That’s why optimizing your subgraph is critical for those using your dapp every day. By improving indexing speed, boosting query performance, and scaling efficiently, you can create a seamless, fast, and reliable experience that keeps users engaged and coming back for more.

In this guide, we share the top 9 tips for subgraph optimization—packed with step-by-step instructions and real-world use cases. Whether you’re powering a DeFi protocol, NFT marketplace, or DAO, these tips will help you maximize your dapp’s potential.


1. Prune Unused Data with indexerHints

Best For: Subgraphs with frequent queries that don’t rely on deep historical data, such as NFT marketplaces and DeFi protocols tracking token prices.

Pruning archival data by reducing the size of your subgraph’s database can significantly improve query speed. When you prune unused data, the database becomes smaller, and more efficiently queried. To achieve this, you can leverage the indexerHints directive which allows you to control how much historical data is retained.

How to Prune a Subgraph:

Add the indexerHints section to your subgraph.yaml file:

indexerHints:

Choose from three pruning options:

  • prune: auto (default): Retains the minimum history required by the Indexer.
  • prune: <number of blocks>: Retains a custom number of historical blocks.
  • prune: never: Retains the entire history (useful for Time Travel Queries).

Read this cookbook to learn more about pruning unused data with indexerHints.


2. Avoid Large Arrays with the @derivedFrom Directive

Best For: Dapps with dynamic relationships, such as blogging platforms or social media dapps.

Large arrays can slow down both indexing and queries as they grow. Using @derivedFrom creates efficient one-to-many relationships, preventing arrays from becoming bloated.

How to Use @derivedFrom:

Update your GraphQL schema to add the directive:

type Post @entity {

id: Bytes!

title: String!

comments: [Comment!]! @derivedFrom(field: "post")

}

type Comment @entity {

id: Bytes!

content: String!

post: Post!

}

The @derivedFrom directive ensures that comments are stored dynamically and don’t overload the "Post" entity.

Read this article to learn more on avoiding large arrays within our subgraphs.


3. Leverage Immutable Entities

Best For: Event-heavy applications like token transfer trackers or transaction analytics dashboards.

Immutable entities are ideal for storing data that doesn't change, such as on-chain events. They improve both indexing and query performance by eliminating unnecessary updates and filters.

How to Define Immutable Entities:

Add the (immutable: true) directive to your schema:

type Transfer @entity(immutable: true) {

id: Bytes!

from: Bytes!

to: Bytes!

value: BigInt!

}

Read this cookbook and this article   to learn more about the performance improvements of using Immutable Entities.


4. Use Bytes for IDs

Best For: Subgraphs requiring high indexing speeds, such as real-time DeFi trackers.

Using Bytes as IDs minimizes storage space and improves comparison efficiency. Avoid string concatenation for IDs, as it can degrade performance.

Best Practices:

Define IDs as Bytes in your GraphQL schema:

id: Bytes!

Concatenate values with the concatI32() method in mappings:

let id = event.transaction.hash.concatI32(event.logIndex.toI32());

Read this cookbook and article to learn more about the performance improvements of using Bytes as IDs.


5. Minimize declarative eth_calls

Best For: Subgraphs indexing DeFi pools, staking contracts, or protocols with state-dependent logic.

eth_calls fetch on-chain data outside of emitted events, slowing indexing. Optimize by emitting all required data in events or minimizing the runtime overhead of necessary eth_calls.

How to Eliminate eth_calls:

Update your smart contracts to emit all required data in events:

event TransferWithPool(address from, address to, uint256 value, bytes32 poolInfo);

Adjust your mapping to index the new event:

export function handleTransferWithPool(event: TransferWithPool): void {

let transaction = new TokenTransaction(event.transaction.hash.toHex());

transaction.pool = event.params.poolInfo.toHexString();

transaction.save();

}

Read this cookbook and this article to learn more about minimizing eth_calls.


6. Implement Time-Series and Aggregations

Best For: Analytics platforms, DEXes, or any application needing time-based metrics.

For subgraphs handling large volumes of time-based data, using time-series entities and aggregations reduces overhead and accelerates queries. Timestamps are key here, as they enable precise organization and retrieval of time-based data, making it easier to analyze trends and patterns over specific intervals.

This approach significantly improves query performance by pre-computing metrics (e.g., sums, averages) over defined intervals (hourly, daily, etc.), reducing the need for complex on-the-fly calculations. Additionally, it provides a structured way to store and retrieve historical data, making it ideal for applications like trading analytics, volume tracking, or performance monitoring.

How to Use Aggregations:

Define a time-series entity:

type Data @entity(timeseries: true) {

id: Int8!

timestamp: Timestamp!

price: BigDecimal!

}

Add an aggregation entity:

type Stats @aggregation(intervals: ["hour", "day"], source: "Data") {

id: Int8!

timestamp: Timestamp!

sum: BigDecimal! @aggregate(fn: "sum", arg: "price")

}

Read this cookbook to learn more about using Timeseries and Aggregations.


7. Use Grafting for Hotfixes

Best For: Critical hotfixes in subgraphs handling financial or real-time applications.

Grafting allows you to reuse indexed data from a previous deployment when deploying updates, saving time and preserving historical data.

How to Implement Grafting:

Add the graft field to your subgraph.yaml:

graft:

base: QmBaseDeploymentID

block: 6000000

Set the base to the previous subgraph’s deployment ID and the block to the last indexed block.

Read this cookbook to learn more about using grafting.


8. Use Substreams-powered Subgraphs

Best For: Enterprise-level indexing performance, large data sets, and data flexibility.

Substreams allow for indexing of raw blockchain data from many chains and are highly performant. They can sink their data into various sinks, including a subgraph.

Read this article and these docs to learn more about implementing a Substreams-powered subgraph.

9. Build Smart Contracts with High-quality Events

Best For: Smart contract developers who plan to index the smart contract’s data.

Considering the events of a smart contract in the early stages of smart contract development is a fundamental consideration for any smart contract developer who plans to index their smart contract.

Read this article to learn more about having an event-driven development mindset when developing smart contracts.

Final Thoughts

Optimizing your subgraphs can significantly enhance your dapp's performance and scalability. Whether you're building a DeFi protocol, NFT marketplace, or social platform, implementing these best practices ensure faster queries, improved indexing speeds, and a better user experience.

What’s Next?

Experiment with these strategies in your subgraphs and share your success stories, so if you’ve achieved great results, share them with us for a chance to be featured! For more in-depth guides, visit The Graph Documentation for the latest updates! Additionally, you can follow GraphDevs on X and DM any time!

About The Graph

The Graph is the source of data and information for the decentralized internet. As the original decentralized data marketplace that introduced and standardized subgraphs, The Graph has become web3’s method of indexing and accessing blockchain data. Since its launch in 2018, tens of thousands of developers have built subgraphs for dapps across 90+ blockchains - including  Ethereum, Solana, Arbitrum, Optimism, Base, Polygon, Celo, Fantom, Gnosis, and Avalanche.

Discover more about how The Graph is shaping the future of decentralized physical infrastructure networks (DePIN) and stay connected with the community. Follow The Graph on X, LinkedIn, Instagram, Facebook, Reddit, Farcaster and Medium. Join the community on The Graph’s Telegram, join technical discussions on The Graph’s Discord.

The Graph Foundation oversees The Graph Network. The Graph Foundation is overseen by the Technical Council. Edge & Node, StreamingFast, Semiotic Labs, Messari, GraphOps, Pinax and Geo are seven of the many organizations within The Graph ecosystem.


Categories
Developer CornerRecommended
Published
January 31, 2025

Edge & Node

View all blog posts