What is a Subgraph?
A subgraph is a declarative specification that describes:- What data to index from a blockchain (events, transactions, blocks)
- How to transform that data (mapping functions in AssemblyScript/WASM)
- What to store (entities defined in a GraphQL schema)
- How to query that data (auto-generated GraphQL API)
Think of a subgraph as a custom API for blockchain data. Instead of scanning through thousands of blocks and transactions, you query a structured database that’s been automatically maintained by Graph Node.
Subgraph Manifest
Every subgraph starts with a manifest file (subgraph.yaml) that serves as its entry point. The manifest specifies all the information required to index and query a specific subgraph.
Manifest Structure
core/src/subgraph_manifest.rs
Key Manifest Components
specVersion
specVersion
Indicates which version of the subgraph manifest specification is being used. Current version is
0.0.4.Starting from specVersion 0.0.4, subgraphs must explicitly declare features they use (like nonFatalErrors, fullTextSearch, grafting, etc.).Reference: docs/subgraph-manifest.md:1-194schema
schema
Points to the GraphQL schema file that defines the entities (data models) your subgraph will store.The schema file can be local or hosted on IPFS.
dataSources
dataSources
Defines the blockchain data sources to index. Each data source specifies:
- kind: Type of data source (e.g.,
ethereum/contract,near/receipt) - name: Identifier for the data source
- network: Blockchain network (mainnet, goerli, etc.)
- source: Contract address, ABI, and start block
- mapping: How to transform the data (handlers, entities, ABIs)
templates
templates
Data source templates enable dynamic data source creation. Templates have the same structure as data sources but without a contract address.Templates are instantiated at runtime when your mapping code calls
DataSourceTemplate.create(address).Use case: Index factory-created contracts (e.g., all Uniswap pairs created by the factory).Data Sources
Data sources define what blockchain data triggers your subgraph’s indexing logic.Data Source Types
Static Data Sources
Defined in the manifest with fixed addresses and start blocks. Begin indexing when Graph Node deploys the subgraph.
Dynamic Data Sources
Created at runtime from templates. Useful for indexing contracts created by factories.
Handler Types
Data sources can define multiple types of handlers:Event Handlers
Event Handlers
Triggered when a specific smart contract event is emitted.Implementation:
chain/ethereum/src/adapter.rs extracts event logs and matches them to handlers.Performance note: Event handlers are the most common and efficient way to index blockchain data.Call Handlers
Call Handlers
Triggered when a specific smart contract function is called.Note: Requires archive node with trace data. More expensive than event handlers.
Block Handlers
Block Handlers
Triggered for every block (or filtered blocks).Filter types:
call: Only process blocks containing calls to the data source contract
Entity Schema
The GraphQL schema defines the data models (entities) your subgraph stores. Graph Node automatically generates database tables and GraphQL queries based on this schema.Schema Example
Supported Field Types
- Scalars:
ID,String,Int,BigInt,BigDecimal,Boolean,Bytes - References: Link to other entities (e.g.,
from: User!) - Arrays: Lists of scalars or references (e.g.,
[Transaction!]!) - Derived fields: Reverse lookups using
@derivedFrom
store/postgres/src/relational.rs generates PostgreSQL tables from the schema.
Mapping Functions
Mapping functions are written in AssemblyScript (compiled to WebAssembly) and define how to transform blockchain data into entities.Mapping Example
Runtime Execution
Mapping functions execute in a sandboxed WebAssembly environment:- Trigger matching:
DataSource::match_and_decode()determines if a trigger matches the data source - WASM invocation:
RuntimeHostinvokes the handler function - Host functions: Mapping code calls host functions to access data and store entities
- Entity operations:
entity.save()persists changes to PostgreSQL
runtime/wasm/src/host_exports.rs implements host functions available to mappings.
Available Host Functions
Entity Operations
entity.save(), Entity.load(), store.remove()Ethereum Data
ethereum.call(), access to block, transaction, event dataIPFS
ipfs.cat(), ipfs.map()Utilities
Crypto functions, JSON parsing, logging
Subgraph Lifecycle
1. Development
2. Deployment
- Files are uploaded to IPFS
- Manifest is validated
SubgraphRegistrarcreates deployment record- Database schema is generated
SubgraphInstanceManagerstarts indexing
core/src/subgraph/registrar.rs, core/src/subgraph/instance_manager.rs
3. Indexing
Once deployed, Graph Node automatically indexes the subgraph:- Block stream creation: Start from
startBlockdefined in manifest - Trigger extraction: Extract relevant events/calls/blocks
- Handler execution: Execute mapping functions for each trigger
- Entity persistence: Store entities to PostgreSQL
- Progress tracking: Update subgraph cursor
core/src/subgraph/runner.rs
4. Querying
Queries are executed against the stored entities:http://localhost:8000/subgraphs/name/my-subgraph
Advanced Features
Grafting
Grafting allows a subgraph to be initialized from another subgraph’s state at a specific block, rather than starting from genesis.docs/subgraph-manifest.md:168-174
Declared Calls
Declared calls areeth_call operations that run in parallel before handler execution, improving sync performance.
ethereum.call().
Available from: specVersion 1.2.0
Reference: docs/subgraph-manifest.md:99-131
Full-Text Search
Enable full-text search on entity fields:fullTextSearch in manifest features.
Subgraph Components in Codebase
SubgraphRegistrar
Handles subgraph deployment and validation
core/src/subgraph/registrar.rsSubgraphInstanceManager
Manages lifecycle of running subgraph instances
core/src/subgraph/instance_manager.rsSubgraphRunner
Executes subgraph indexing logic
core/src/subgraph/runner.rsRuntimeHost
WASM runtime for executing mappings
runtime/wasm/src/host.rsBest Practices
Performance tip: Use event handlers whenever possible. They’re more efficient than call handlers and don’t require archive nodes.
- Start block optimization: Set
startBlockto the deployment block of your contract to avoid indexing unnecessary blocks - Entity design: Use derived fields instead of storing redundant data
- Handler efficiency: Minimize entity loads and saves in handlers
- ID strategy: Use deterministic IDs (e.g., transaction hash + log index) to ensure uniqueness
- Error handling: Handle null cases when loading entities
Next Steps
Indexing Process
Learn how Graph Node processes blocks and executes handlers
Query Execution
Understand how queries are translated to SQL and optimized
Architecture
Explore Graph Node’s overall architecture
Subgraph Manifest Spec
Full subgraph manifest specification

