Build an Indexer from Scratch
This guide demonstrates how SDK packages can be combined into a working indexer (called a squid). This page goes through all the technical details to make the squid architecture easier to understand. If you want to get to a working indexer ASAP, bootstrap from a template.Prerequisites
Before you begin, ensure you have:- Node.js 20.x or newer - Download here
- Docker - Download here
Project: USDT Transfers API
In this tutorial, you’ll build an indexer that tracks USDT transfers on Ethereum, saves the data to PostgreSQL, and serves it as a GraphQL API.Required packages
From the requirements above, you’ll need these packages:@subsquid/evm-stream- for retrieving Ethereum data from a SQD Network Portal@subsquid/batch-processor- for running the data source against a batch handler@subsquid/evm-objects- for enriching the retrieved blocks with item IDs and navigation helpers@subsquid/typeorm-store,@subsquid/typeorm-codegen, and@subsquid/typeorm-migration- for saving data to PostgreSQL
Optional packages
@subsquid/evm-typegen- for decoding Ethereum data and useful constants such as event topic0 values@subsquid/evm-abiand@subsquid/evm-codec- runtime dependencies imported by the code generated by@subsquid/evm-typegen@subsquid/graphql-server/ OpenReader - for serving GraphQL API
Build the Indexer
1
Initialize the project
Create a new folder and initialize a Node.js project:Create a
.gitignore file:.gitignore
2
Install dependencies
Install the required packages:Install development dependencies:
3
Configure TypeScript
Create a
tsconfig.json file with minimal configuration:tsconfig.json
4
Define the data schema
Create a Generate TypeORM classes from the schema:
schema.graphql file to define your data model:schema.graphql
The TypeORM classes are now available at
src/model/index.ts.5
Set up the database
Create environment variables in a Create a Start the database:Compile the TypeORM classes:Generate and apply the database migration:
.env file:.env
docker-compose.yaml file for PostgreSQL:docker-compose.yaml
6
Generate ABI utilities
Create an Find the USDT contract ABI on Etherscan and save it to
abi folder for contract ABIs:./abi/usdt.json.Generate TypeScript utility classes from the ABI:The utility classes are now available in
src/abi/usdt/, with an index.ts entry point. Typegen v5 removes a stale src/abi/usdt.ts file from the older single-file layout.7
Create the data source and the batch handler
Create The public Portal needs no RPC endpoint of your own, and the stream covers everything from historical blocks to the real-time chain head. Note that field selection is explicit: there are no default optional fields, so we list every log field the handler reads (the decoder needs With
src/main.ts with the following code blocks:Imports
main.ts
Data source configuration
main.ts
topics and data).Database configuration
main.ts
supportHotBlocks: true the store can consume unfinalized blocks and roll the data back automatically on chain reorganizations.Batch handler
main.ts
augmentBlock() from @subsquid/evm-objects enriches the raw block items with unique IDs (used here as entity IDs) and navigation helpers — see Context interfaces.8
Run the indexer
Compile the project:Start the indexer:
The indexer is now processing USDT transfers from the Ethereum blockchain.
9
Start the GraphQL server
Update your In a separate terminal, start the GraphQL server:
.env file to include the GraphQL server port:.env
The GraphQL API with GraphiQL is available at
localhost:4350/graphql.
Next Steps
Congratulations! You’ve built a complete blockchain indexer from scratch.View Complete Code
See the final code for this tutorial
Development Flow
Learn about the general development workflow