> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Bootstrap a Pipes SDK project

# 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](/en/ai/agent-skills#pipes-sdk-skill):

```bash theme={"system"}
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](/en/ai/mcp-server) — 29 tools for querying blocks, transactions, logs, instructions, and analytics across 225+ datasets. No API key.
* [Documentation MCP server](/en/ai/mcp-server-docs) — search and retrieve these docs from inside the agent.

If you'd rather feed docs into a model directly, the static [`llms.txt`](https://docs.sqd.dev/llms.txt) (index) and [`llms-full.txt`](https://docs.sqd.dev/llms-full.txt) (full content) files are kept in sync with the site. See the [AI Development overview](/en/ai/ai-development) for the full menu.

# Scaffolding with Pipes CLI

<Note>
  `pipes-cli` is a work in progress.
</Note>

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:

```bash theme={"system"}
pnpx @subsquid/pipes-cli@1.0.0-alpha.4 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:

```bash theme={"system"}
pnpx @subsquid/pipes-cli@1.0.0-alpha.4 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/pipes-cli@1.0.0-alpha.4 init --schema
```

## Run the pipeline

The generated project ships with a `docker-compose.yml` that brings up the sink database and the pipeline together:

```bash theme={"system"}
cd usdc-example
docker compose --profile with-pipeline up
```

For an iterative dev loop, run the database in Docker and the pipeline locally:

```bash theme={"system"}
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:

```ts theme={"system"}
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](./guides/basic-development/anatomy) and [Handling contract events](./guides/basic-development/handling-events) guides for more info on `evmDecoder()`.

The `main()` function wires the decoder to a [drizzleTarget](./reference/basic-components/target/postgres-drizzle):

```ts theme={"system"}
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](./guides/architecture-deep-dives/cursor-management) survives restarts. See [evmPortalSource](./reference/basic-components/source) for the full source API and [Pipe anatomy](./guides/basic-development/anatomy) for how the pieces fit together.

## Other examples

<AccordionGroup>
  <Accordion title="Uniswap V3 swaps via factory">
    Tracks every pool created by the Uniswap V3 factory and indexes its `Swap` events. The generated decoder uses [factory transformers](./guides/advanced-topics/factory-transformers) with a SQLite-backed pool registry.

    ```bash theme={"system"}
    pnpx @subsquid/pipes-cli@1.0.0-alpha.4 init --config '{
      "projectFolder": "uniswapv3-swaps",
      "packageManager": "pnpm",
      "sink": "postgresql",
      "networkType": "evm",
      "network": "ethereum-mainnet",
      "templates": [
        {
          "templateId": "uniswapV3Swaps",
          "params": {
            "factoryAddress": "0x1f98431c8ad98523631ae4a59f267346ea31f984",
            "range": { "from": "latest" }
          }
        }
      ]
    }'
    ```
  </Accordion>

  <Accordion title="Aave V3 supply / withdraw (custom template)">
    The `custom` template generates ABI bindings and decoder wiring from an event list you provide. Drop in any contract and event set.

    ```bash theme={"system"}
    pnpx @subsquid/pipes-cli@1.0.0-alpha.4 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" }
              }
            ]
          }
        }
      ]
    }'
    ```
  </Accordion>
</AccordionGroup>

The CLI ships two built-in EVM templates — `erc20Transfers` and `uniswapV3Swaps` — plus the open-ended `custom` template.
