Skip to main content

Documentation Index

Fetch the complete documentation index at: https://beta.docs.sqd.dev/llms.txt

Use this file to discover all available pages before exploring further.

Using with AI

The fastest way to get an AI coding agent productive on a Pipes SDK project is to install the official Pipes SDK Agent Skill:
npx skills add subsquid-labs/skills/pipes-sdk
The skill activates automatically on tasks like “create an indexer for Uniswap V3 swaps” or “my indexer is syncing slowly, help me optimize it”. It covers scaffolding, runtime error diagnosis, sync tuning, and data-quality checks. Pair the skill with one or both MCP servers so the agent can read live data and look things up:
  • Portal MCP server — 29 tools for querying blocks, transactions, logs, instructions, and analytics across 225+ datasets. No API key.
  • Documentation MCP server — search and retrieve these docs from inside the agent.
If you’d rather feed docs into a model directly, the static llms.txt (index) and llms-full.txt (full content) files are kept in sync with the site. See the AI Development overview for the full menu.

Scaffolding with Pipes CLI

pipes-cli is a work in progress.
In a few minutes, you’ll have a running pipe that indexes USDC token transfers on Ethereum mainnet into a local PostgreSQL database.

Prerequisites

  • Node.js 22.15+
  • pnpm
  • Docker (for the bundled PostgreSQL container)

Initialize the project

Run the CLI in the directory where you want the project folder to land:
pnpx @subsquid/[email protected] init
The CLI prompts for the project folder name, package manager (please stick to pnpm for now), sink (please use ClickHouse or Postgres), network type, network, and template; then installs dependencies and writes a runnable project. You can supply a JSON config instead of filling the prompts manually. Here’s the configuration for USDC token transfers mentioned above:
pnpx @subsquid/[email protected] init --config '{
  "projectFolder": "usdc-example",
  "packageManager": "pnpm",
  "sink": "postgresql",
  "networkType": "evm",
  "network": "ethereum-mainnet",
  "templates": [
    {
      "templateId": "erc20Transfers",
      "params": {
        "contractAddresses": ["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"],
        "range": { "from": "latest" }
      }
    }
  ]
}'
--config also accepts a path to a JSON file. To inspect the full config schema run
pnpx @subsquid/[email protected] init --schema

Run the pipeline

The generated project ships with a docker-compose.yml that brings up the sink database and the pipeline together:
cd usdc-example
docker compose --profile with-pipeline up
For an iterative dev loop, run the database in Docker and the pipeline locally:
docker compose up -d         # Postgres on :5432
pnpm run db:migrate          # apply the generated migration
pnpm run dev                 # tsx src/index.ts
Either way, rows start landing in the erc20_transfers table within a minute.

What was generated

The project layout:
usdc-example/
├── src/
│   ├── index.ts        # the pipe — source, decoder, target
│   ├── schemas.ts      # Drizzle table definitions
│   └── utils/
├── migrations/         # SQL migrations generated by drizzle-kit
├── docker-compose.yml  # Postgres + optional pipeline service
├── Dockerfile
├── drizzle.config.ts
├── package.json
├── .env                # DB_CONNECTION_STR — points at local Postgres
└── README.md
The pipe lives in src/index.ts. The decoder block defines what to extract + a light transform:
const erc20Transfers = evmDecoder({
  profiler: { name: 'erc20-transfers' },
  range: { from: 'latest' },
  contracts: ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
  events: { transfers: commonAbis.erc20.events.Transfer },
}).pipe(({ transfers }) =>
  transfers.map((transfer) => ({
    blockNumber: transfer.block.number,
    txHash: transfer.rawEvent.transactionHash,
    logIndex: transfer.rawEvent.logIndex,
    timestamp: transfer.timestamp.getTime(),
    from: transfer.event.from,
    to: transfer.event.to,
    value: transfer.event.value,
    tokenAddress: transfer.contract,
  })),
)
This query-transform combo asks the Portal for ERC20 Transfer logs from the USDC contract, decodes them and (in the .pipe step) reshapes each one into a row matching the Drizzle table. See the Pipe anatomy and Handling contract events guides for more info on evmDecoder(). The main() function wires the decoder to a drizzleTarget:
export async function main() {
  await evmPortalSource({
    id: 'ethereum-usdc-pipe',
    portal: 'https://portal.sqd.dev/datasets/ethereum-mainnet',
    outputs: { erc20Transfers },
  }).pipeTo(
    drizzleTarget({
      db: drizzle(env.DB_CONNECTION_STR),
      tables: [erc20TransfersTable],
      onData: async ({ tx, data }) => {
        for (const values of chunk(data.erc20Transfers)) {
          await tx.insert(erc20TransfersTable).values(values)
        }
      },
    }),
  )
}
The id is a per-pipeline identifier — keep it stable so the target’s cursor survives restarts. See evmPortalSource for the full source API and Pipe anatomy for how the pieces fit together.

Other examples

Tracks every pool created by the Uniswap V3 factory and indexes its Swap events. The generated decoder uses factory transformers with a SQLite-backed pool registry.
pnpx @subsquid/[email protected] init --config '{
  "projectFolder": "uniswapv3-swaps",
  "packageManager": "pnpm",
  "sink": "postgresql",
  "networkType": "evm",
  "network": "ethereum-mainnet",
  "templates": [
    {
      "templateId": "uniswapV3Swaps",
      "params": {
        "factoryAddress": "0x1f98431c8ad98523631ae4a59f267346ea31f984",
        "range": { "from": "latest" }
      }
    }
  ]
}'
The custom template generates ABI bindings and decoder wiring from an event list you provide. Drop in any contract and event set.
pnpx @subsquid/[email protected] init --config '{
  "projectFolder": "aave-supply-withdraw",
  "packageManager": "pnpm",
  "sink": "postgresql",
  "networkType": "evm",
  "network": "ethereum-mainnet",
  "templates": [
    {
      "templateId": "custom",
      "params": {
        "contracts": [
          {
            "contractAddress": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
            "contractName": "AaveV3Pool",
            "contractEvents": [
              {
                "anonymous": false,
                "inputs": [
                  { "indexed": true, "name": "reserve", "type": "address" },
                  { "indexed": false, "name": "user", "type": "address" },
                  { "indexed": true, "name": "onBehalfOf", "type": "address" },
                  { "indexed": false, "name": "amount", "type": "uint256" },
                  { "indexed": true, "name": "referralCode", "type": "uint16" }
                ],
                "name": "Supply",
                "type": "event"
              },
              {
                "anonymous": false,
                "inputs": [
                  { "indexed": true, "name": "reserve", "type": "address" },
                  { "indexed": true, "name": "user", "type": "address" },
                  { "indexed": true, "name": "to", "type": "address" },
                  { "indexed": false, "name": "amount", "type": "uint256" }
                ],
                "name": "Withdraw",
                "type": "event"
              }
            ],
            "range": { "from": "latest" }
          }
        ]
      }
    }
  ]
}'
The CLI ships two built-in EVM templates — erc20Transfers and uniswapV3Swaps — plus the open-ended custom template.