Skip to main content

Lesson 2: Getting started with SubQuery

SubQuery TeamAbout 3 min

Lesson 2: Getting started with SubQuery

It’s the high time we start coding. Let’s build our first SubQuery project with the help of SubQuery CLI!

In this lesson, we will:

  • Initialise the project through SubQuery CLI
  • Get familiar with the project structure
  • Index EVM events
  • Deploy the project locally with docker

1. Preparation

Environment and dependencies

Installation of the SubQuery CLI

Install SubQuery CLI globally on your terminal with NPM:

npm install -g @subql/cli


Note that we don't encourage the use of yarn global for installing @subql/cli due to its poor dependency management. This may lead to multiple errors.

Then check the subql cli version by running the given below command:

subql -v

Run help to see available commands provided by SubQuery CLI:

subql help

2. Initialise the SubQuery Starter Project

Inside the directory in which you want to create the SubQuery project run the following command and follow all the steps chosing project name, GitHub repo addres, network family, rpc endpoint and more. Follow steps from the video.

Find out more about initialisation of SubQuery projects in our Quick Start Guide.

subql init project-name


Remember that, everything in the project configuration can by changed afterwards as well.

Then you should see a folder with your project name has been created inside the directory, you can use this as the start point of your project. And the files should be identical as in the Directory Structure.

3. SubQuery Project Structure

If you want to change your project and go beyond the default content of any starter project built with SubQuery CLI, you will need to work on the following files:

  • The Manifest in project.yaml to configure your project.
  • The GraphQL Schema in schema.graphql to define shape of the data.
  • The Mapping functions in src/mappings/ directory to transform data coming from blockchain.

Find out more about Manifest and GraphQl Schema and Mapping functions in our documentation.


In this first lesson there is no code alternation.

After the initialisation of the starter project your files should look like this:


specVersion: 1.0.0
name: moonbeam-evm-starter
version: 0.0.1
    name: "@subql/node"
    version: ">=0.35.0"
    name: "@subql/query"
    version: ">=0.16.0"
description: Moonbeam / SubQuery Course — Building dApps with the help of SubQuery
repository: ""
  file: ./schema.graphql
  chainId: "0x401a1f9dca3da46f5c4091016c8a2f26dcea05865116b286f60f668207d1474b"
  endpoint: "wss://"
  dictionary: ""
    file: ./dist/chaintypes.js
  - kind: substrate/FrontierEvm
    startBlock: 752073
      file: ./node_modules/@subql/frontier-evm-processor/dist/bundle.js
        abi: erc20
        address: "0x6bd193ee6d2104f14f94e2ca6efefae561a4334b"
        file: ./erc20.abi.json
      file: ./dist/index.js
        - handler: handleFrontierEvmEvent
          kind: substrate/FrontierEvmEvent
              - "Transfer(address indexed from,address indexed to,uint256 value)"
              - null
              - null
              - null
        - handler: handleFrontierEvmCall
          kind: substrate/FrontierEvmCall
            function: "approve(address to,uint256 value)"

Schema GraphQl

type Transaction @entity {
  id: ID! # Transaction hash
  value: BigInt!
  to: String!
  from: String!
  contractAddress: String!

type Approval @entity {
  id: ID! # Transaction hash
  value: BigInt!
  owner: String!
  spender: String!
  contractAddress: String!

Mapping functions

import { Approval, Transaction } from "../types";
import {
} from "@subql/frontier-evm-processor";
import { BigNumber } from "ethers";

// Setup types from ABI
type TransferEventArgs = [string, string, BigNumber] & {
  from: string;
  to: string;
  value: BigNumber;
type ApproveCallArgs = [string, BigNumber] & {
  _spender: string;
  _value: BigNumber;

export async function handleFrontierEvmEvent(
  event: FrontierEvmEvent<TransferEventArgs>,
): Promise<void> {
  const transaction = new Transaction(event.transactionHash);

  transaction.value = event.args.value.toBigInt();
  transaction.from = event.args.from; =;
  transaction.contractAddress = event.address;


export async function handleFrontierEvmCall(
  event: FrontierEvmCall<ApproveCallArgs>,
): Promise<void> {
  const approval = new Approval(event.hash);

  approval.owner = event.from;
  approval.value = event.args._value.toBigInt();
  approval.spender = event.args._spender;
  approval.contractAddress =;


4. Building the Project

Install dependencies

Under the project directory, install the node dependencies by running the following command:

yarn install

Generate Associated Typescript

Next, generate the associated typescript with the following command:

yarn codegen

Build the Project

Next, use following command to bundle the app into static files for production:

yarn build

5. Indexing and Query

Run Docker

Under the project directory run following command:

yarn start:docker

This will download packages from Docker, create a new Postgres database, and start an indexing an query service.


When you are doing it for the first time, it may take some time to start.

Query this Project

Open your browser and head to http://localhost:3000. You should see a GraphQL playground is showing in the explorer and the schemas that ready to query. With this project can try to query with the following code to get a taste of how it works.

query {
  approvals(first: 5) {
    nodes {
  transactions(first: 5) {
    nodes {
      to: id
      from: id

Useful resources


The project's code state after this lesson is hereopen in new window. The final code of this project can be found hereopen in new window.