Skip to main content

Substrate Quickstart

This 5-minute tutorial shows you how to build a Substrate indexer using Squid SDK. You’ll create a complete blockchain indexer that fetches, decodes, and serves Substrate chain data.

What you’ll build

Your Substrate indexer (squid) will:
  • Fetch historical Substrate events and calls from the SQD Network
  • Decode pallet-specific data with runtime version awareness
  • Save the data to a local PostgreSQL database
  • Start a GraphQL server with a rich API to query the indexed data
This tutorial focuses on Substrate chains like Polkadot and Kusama. For other chains, see the EVM Quickstart or Solana Quickstart.

Prerequisites

Before you begin, ensure you have:
1

Install Squid CLI

Install the Squid CLI globally:
npm i -g @subsquid/cli
Verify installation by running sqd --version
Squid CLI is a multi-purpose utility tool for scaffolding and managing indexers, both locally and in SQD Cloud.
2

Scaffold the indexer project

Create a new Substrate squid project:
sqd init hello-substrate-squid -t substrate
cd hello-substrate-squid
The template provides a pre-configured project structure for indexing Substrate-based blockchains.
3

Inspect the project structure

Explore the ./src folder:
src/
├── main.ts
├── processor.ts
└── model
    ├── generated
   ├── index.ts
   └── transfer.model.ts
    └── index.ts
Key files explained: - src/model/ - TypeORM model classes auto-generated from schema.graphql for database operations - processor.ts - Processor configuration for data retrieval - main.ts - Main executable containing processing logic
The processor configuration for Substrate:
processor.ts
export const processor = new SubstrateBatchProcessor()
  // SQD Network gateway for the Substrate chain
  .setGateway("https://v2.archive.subsquid.io/network/polkadot")
  // Optional RPC endpoint for real-time data
  .setRpcEndpoint("<substrate-rpc-endpoint>")
  // Configure block range
  .setBlockRange({ from: 1000000 })
  // Add events to index
  .addEvent({
    name: ["Balances.Transfer"],
    call: true,
    extrinsic: true,
  })
  // Select fields to retrieve
  .setFields({
    event: {
      args: true,
      extrinsic: {
        hash: true,
        fee: true,
      },
    },
  });
The data processing and storage logic:
main.ts
processor.run(new TypeormDatabase({ supportHotBlocks: true }), async (ctx) => {
  const transfers = [];

  for (let block of ctx.blocks) {
    for (let event of block.events) {
      if (event.name === "Balances.Transfer") {
        // Decode event data with runtime version awareness
        const { from, to, amount } = getTransferEvent(ctx, event);

        transfers.push(
          new Transfer({
            id: event.id,
            blockNumber: block.header.height,
            timestamp: new Date(block.header.timestamp),
            extrinsicHash: event.extrinsic?.hash,
            from,
            to,
            amount,
          })
        );
      }
    }
  }

  // Batch insert all transfers
  await ctx.store.save(transfers);
});
4

Install dependencies and build

Install dependencies and build the project:
npm i
npm run build
Verify the build completed successfully by checking for the lib/ directory.
5

Start the database and processor

The processor continuously fetches data, decodes it, and stores it in PostgreSQL. All logic is defined in main.ts and is fully customizable.First, start a local PostgreSQL database (the template includes a Docker Compose file):
docker compose up -d
The processor connects to PostgreSQL using connection parameters from .env. Ensure the database is running before proceeding.
Apply database migrations:
npx squid-typeorm-migration apply
Then start the processor:
node -r dotenv/config lib/main.js
The indexer is now running and will begin processing Substrate blocks.
6

Start the GraphQL API

Start the GraphQL API to serve the indexed data:
npx squid-graphql-server
The GraphQL playground is available at localhost:4350/graphql
7

Query the data

You can now query your indexed Substrate data! Try this example query in the GraphQL playground:
{
  transfers(limit: 10) {
    id
    blockNumber
    timestamp
    from
    to
    amount
  }
}
Congratulations! You’ve successfully built and deployed your first Substrate blockchain indexer.