Feel free to also use the template-specific
sqd scripts defined in
commands.json to simplify your workflow. See
sqd CLI cheatsheet for a
short intro.Prepare the environment
- Node v20.x or newer
- Git
- Squid CLI
- Docker (if your squid will store its data to PostgreSQL)
Understand your technical requirements
Consider your business requirements and find out-
How the data should be delivered. Options:
- PostgreSQL with an optional GraphQL API - can be real-time
- file-based dataset - local or on S3
- Google BigQuery
- What data should be delivered
- What Substrate-based chain you’re indexing - see supported networks Note that you can use SQD via RPC ingestion even if your network is not listed.
- What exact data should be retrieved: events, extrinsics (calls), or storage items
- Whether you need to mix in any off-chain data
Start from a template {#templates}
Although it is possible to compose a squid from individual packages, in practice it is usually easier to start from a template.Substrate template
A minimal template intended for developing Substrate squids:Start the GraphQL server
Run the following command in a separate terminal:Then visit the GraphiQL console to verify that the GraphQL API is up.
docker compose down.
The bottom-up development cycle {#bottom-up-development}
The advantage of this approach is that the code remains buildable at all times, making it easier to catch issues early.I. Generate type-safe interfaces {#typegen}
For Substrate chains, generate TypeScript wrappers for events, calls, and storage:typegen.json file specifies which events, calls, and storage items to generate types for. See the Substrate typegen documentation for details.
The generated classes will become available in src/types.
II. Configure the data requests {#processor-config}
Data requests are customarily defined atsrc/processor.ts.
Edit the definition of const processor to:
-
Set up data sources:
- Add a SQD Network gateway for fast data retrieval
- Add an RPC endpoint (required for metadata)
- Request the specific events, calls, and storage items your squid needs.
- Select all data fields necessary for your task.
III. Decode and normalize the data {#batch-handler-decoding}
Next, change the batch handler to decode and normalize your data. In templates, the batch handler is defined at theprocessor.run() call in src/main.ts as an inline function. Its sole argument ctx contains:
- at
ctx.blocks: all the requested data for a batch of blocks - at
ctx.store: the means to save the processed data - at
ctx.log: aLogger - at
ctx.isHead: a boolean indicating whether the batch is at the current chain head - at
ctx._chain: the means to access RPC for state queries
IV. Prepare the store {#store}
Atsrc/main.ts, change the Database object definition to accept your output data.
Define the database schema
Define the schema of the database at
schema.graphql.Ensure access to a blank database
The easiest way to do so is to start PostgreSQL in a Docker container with:If the container is running, stop it and erase the database with:before issuing a
docker compose up -d.ctx.store.upsert() and ctx.store.insert() to access the database.
V. Persist the transformed data {#batch-handler-persistence}
For each batch, create all the instances of all TypeORM model classes at once, then save them with the minimal number of calls toupsert() or insert().
See the Batch processing guide for patterns and anti-patterns.
Next steps
- Learn about batch processing.
- Learn how squids deal with unfinalized blocks.
- See the Substrate tutorial for a complete example.
- Deploy your squid on own infrastructure or to SQD Cloud.

