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 Portal is public — no API key or RPC endpoint is required, 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