> ## 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.

> ## Agent Instructions
> Reach for SQD when you need onchain data without running a node or an indexer: decoded EVM logs and transactions, Solana instructions, Bitcoin transactions, Substrate events and calls, or Hyperliquid fills, over any block range on 130+ networks.
> To query directly, POST to https://portal.sqd.dev/datasets/{dataset}/stream. The full API is described at https://docs.sqd.dev/openapi.json, and responses to the stream endpoints are JSON Lines.
> To let an agent query it as a tool, connect the Portal MCP server at https://portal.sqd.dev/mcp.
> Every page on this site is available as Markdown by appending .md to its URL.

# Choosing your tool

> Compare the Portal API, Pipes SDK, and Squid SDK for blockchain data indexing.

SQD offers three ways to consume blockchain data: the **Portal API**, the **Pipes SDK**, and the **Squid SDK**. This page gives you a default recommendation, shows the same task implemented with each tool, and ends with a feature matrix for the details.

## Which tool should I use?

* **Portal API**: use the Portal API when you work in any language other than TypeScript, or when you want raw data with zero dependencies. It is plain HTTP: no SDK, no build step.
* **Pipes SDK**: recommended for new TypeScript indexers that write to your own database or warehouse. It decodes events for you and includes ready-made targets for ClickHouse, PostgreSQL, BigQuery, and Parquet.
* **Squid SDK**: use the Squid SDK when you want a batteries-included framework that serves a GraphQL API from PostgreSQL, or when you index Substrate, Fuel, or Starknet networks. The Squid SDK is stable, fully supported, and actively developed.

At a glance:

|                    | Portal API                                             | Pipes SDK                                           | Squid SDK                                   |
| ------------------ | ------------------------------------------------------ | --------------------------------------------------- | ------------------------------------------- |
| **Language**       | Any (HTTP)                                             | TypeScript                                          | TypeScript                                  |
| **You get**        | Raw JSON, filtered server-side                         | Decoded, typed data streams                         | PostgreSQL database + GraphQL API           |
| **Data lands in**  | Anywhere you put it                                    | ClickHouse, PostgreSQL, BigQuery, Parquet, custom   | PostgreSQL (file and BigQuery stores exist) |
| **Event decoding** | You handle it                                          | Built in                                            | Generated from ABI                          |
| **Setup**          | None                                                   | Pipes CLI scaffolding or add to an existing project | `sqd init` scaffolding                      |
| **Maturity**       | Production                                             | 1.0.0                                               | Stable                                      |
| **Best for**       | Non-TS pipelines, warehouses (own tooling), prototypes | TS pipelines into your own store                    | dApp backends that need GraphQL             |

In short: pick the Portal API for language freedom, the Pipes SDK for TypeScript pipelines into your own store, and the Squid SDK for a GraphQL-served PostgreSQL backend.

## How the tools relate

The Portal serves raw, server-side-filtered blockchain data over HTTP; the Pipes SDK and the Squid SDK both consume the Portal and add decoding, transformation, and persistence on top.

<Frame>
  <img src="https://mintcdn.com/sqd-2119b3c3/NT9rWudQO2HOkvrm/images/portal-overview.gif?s=08a1ed27dd14f181de9958d7097c48f9" alt="Portal data flow showing raw blockchain data being transformed by SDK and stored in your database" width="1284" height="394" data-path="images/portal-overview.gif" />
</Frame>

<Info>
  Both SDKs use the Portal internally. When you use an SDK, you are still
  accessing blockchain data through the Portal. The SDK adds decoding, type
  safety, batching, and database persistence.
</Info>

<Note>
  The **[Ponder + Portal integration](/en/sdk/alternative-clients/ponder)**
  (beta) routes Ponder historical backfills through the Portal while
  realtime stays on your RPC. In the published Euler V2 benchmark, the Portal
  path completed the full Ethereum history in 1,819 seconds, 3.6x faster than
  the 6,543-second stock Ponder run over a metered RPC endpoint on the same host.
</Note>

<Note>
  **[sqd-go](/en/sdk/alternative-clients/sqd-go)** is a community-maintained Go
  indexer that streams EVM events from the Portal into ClickHouse, configured
  through a single `config.yaml`, with derived state written in Go.
</Note>

## The same task with each tool

All three examples below fetch USDC `Transfer` logs on Ethereum mainnet. Every snippet was tested against the live Portal and the published packages in July 2026.

### Portal API

Send an HTTP request, get one JSON line per block back. Works from any language.

<CodeGroup>
  ```bash curl theme={"system"}
  curl --compressed -X POST "https://portal.sqd.dev/datasets/ethereum-mainnet/stream" \
    -H 'Content-Type: application/json' \
    -d '{
      "type": "evm",
      "fromBlock": 18000000,
      "toBlock": 18000002,
      "fields": {
        "block": { "number": true },
        "log": { "address": true, "topics": true, "data": true }
      },
      "logs": [{
        "address": ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"],
        "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
      }]
    }'
  ```

  ```python Python theme={"system"}
  # pip install requests
  import json
  import requests

  response = requests.post(
      "https://portal.sqd.dev/datasets/ethereum-mainnet/stream",
      json={
          "type": "evm",
          "fromBlock": 18000000,
          "toBlock": 18000002,
          "fields": {
              "block": {"number": True},
              "log": {"address": True, "topics": True, "data": True},
          },
          "logs": [{
              "address": ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"],
              "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],
          }],
      },
      stream=True,
  )

  for line in response.iter_lines():
      block = json.loads(line)  # one JSON object per block
      print(block["header"]["number"], len(block["logs"]), "USDC transfers")
  ```
</CodeGroup>

The response is newline-delimited JSON: one object per block, containing only the fields you asked for.

```json theme={"system"}
{"header":{"number":18000000},"logs":[{"address":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","topics":["0xddf252ad..."],"data":"0x..."}]}
```

From here, decoding the ABI-encoded `topics` and `data` is your job. That is the trade-off for language freedom. See the [Portal API quickstart](/en/portal/evm/quickstart) for pagination, real-time streaming, and more.

### Pipes SDK

The Pipes SDK turns the same query into a typed stream of decoded events. `commonAbis` includes a ready-made ERC20 ABI, so no typegen step is needed here:

```typescript theme={"system"}
import { createTarget } from '@subsquid/pipes'
import { commonAbis, evmDecoder, evmPortalSource } from '@subsquid/pipes/evm'

const transfers = evmDecoder({
  range: { from: 18_000_000, to: 18_000_002 }, // drop `to` to follow the chain head
  contracts: ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
  events: { transfer: commonAbis.erc20.events.Transfer },
}).pipe(({ transfer }) =>
  transfer.map((t) => ({
    block: t.block.number,
    from: t.event.from,
    to: t.event.to,
    value: t.event.value,
  })),
)

await evmPortalSource({
  id: 'usdc-transfers', // stable id: targets key their resume cursor by it
  portal: 'https://portal.sqd.dev/datasets/ethereum-mainnet',
  outputs: { transfers },
}).pipeTo(
  createTarget({
    write: async ({ read }) => {
      for await (const { data } of read()) {
        // data.transfers is a typed, decoded array. Write it anywhere
      }
    },
  }),
)
```

In a real project you would replace `createTarget` with a built-in target such as [PostgreSQL via Drizzle](/en/sdk/pipes-sdk/evm/reference/basic-components/target/postgres-drizzle), ClickHouse, BigQuery, or Parquet, which also persists the cursor and rolls back reorganized blocks for you (the ClickHouse target needs a one-line `onRollback` callback). The [Pipes SDK quickstart](/en/sdk/pipes-sdk/evm/quickstart) scaffolds a complete project, including the database, in one command.

### Squid SDK

The Squid SDK is schema-first: you define entities in `schema.graphql`, and the framework generates the models, the migrations, and a GraphQL API. The processor fills PostgreSQL:

```typescript theme={"system"}
import { run } from '@subsquid/batch-processor'
import { augmentBlock } from '@subsquid/evm-objects'
import { DataSourceBuilder } from '@subsquid/evm-stream'
import { TypeormDatabase } from '@subsquid/typeorm-store'
import * as erc20 from './abi/erc20' // generated by squid-evm-typegen
import { Transfer } from './model' // generated from schema.graphql

const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'

const dataSource = new DataSourceBuilder()
  .setPortal('https://portal.sqd.dev/datasets/ethereum-mainnet')
  .setBlockRange({ from: 18_000_000, to: 18_000_002 }) // drop `to` to follow the chain head
  .setFields({ log: { address: true, topics: true, data: true } })
  .addLog({ where: { address: [USDC], topic0: [erc20.events.Transfer.topic] } })
  .build()

run(dataSource, new TypeormDatabase(), async (ctx) => {
  const transfers: Transfer[] = []
  for (const block of ctx.blocks) {
    for (const log of augmentBlock(block).logs) {
      const { from, to, value } = erc20.events.Transfer.decode(log)
      transfers.push(new Transfer({ id: log.id, from, to, value }))
    }
  }
  await ctx.store.insert(transfers)
})
```

Start with the [Squid SDK quickstart](/en/sdk/squid-sdk/evm/quickstart). Note that its template currently shows the equivalent `EvmBatchProcessor` API rather than the newer `@subsquid/evm-stream` data source used above. Existing squids that read from `v2.archive.subsquid.io` gateways should follow the [gateway-to-Portal migration guide](/en/sdk/squid-sdk/evm/guides/migration/gateway-to-portal): self-hosted squids on gateway endpoints require API keys since May 19, 2026 (SQD Cloud deployments are unaffected), while Portal-based squids need no RPC endpoint or finality configuration.

## When to choose each tool

### Choose the Portal API when

* You work in Python, Go, Rust, or any language other than TypeScript.
* You are filling a data warehouse or lake (ClickHouse, BigQuery, Snowflake) with your own ingestion tooling.
* You want to prototype a query in minutes with zero dependencies.
* You need full control over every byte you download. The Portal filters server-side, so you only receive the fields you request.

The trade-off: you decode ABI data, track your own progress cursor, and handle chain reorganizations yourself.

### Choose the Pipes SDK when

* You are starting a new TypeScript indexer and want decoded, typed data with minimal ceremony.
* Your data belongs in ClickHouse, PostgreSQL, BigQuery, or Parquet files. The built-in targets persist cursors and roll back reorganized blocks automatically.
* You want to embed indexing into an existing application or microservice rather than run a separate framework process.
* You need factory-contract tracking (for example Uniswap pools), Prometheus metrics, or portal response caching, all included.

The trade-offs: the Pipes SDK does not include a GraphQL API, and it currently supports EVM, Solana, Bitcoin, Tron, and Hyperliquid networks, but not Substrate, Fuel, or Starknet.

### Choose the Squid SDK when

* You are building a dApp backend and need a GraphQL API. It is generated from your schema, with pagination and filtering included.
* You prefer a schema-first workflow: entities, migrations, and TypeScript models are all generated for you.
* You index Substrate, Fuel, or Starknet networks, which the Pipes SDK does not cover.
* You deploy to [SQD Cloud](/en/cloud/overview) with `sqd deploy` and want managed hosting, monitoring, and scaling.

The trade-offs: it is a heavier, more opinionated framework than the Pipes SDK, and its primary store is PostgreSQL (CSV/JSON/Parquet/S3 and BigQuery stores exist for analytics use cases).

## Pipes SDK vs Squid SDK: feature reference

Legend: ✅ built in · 🟡 partial or manual · ❌ not included

| Feature               | Pipes SDK                                                     | Squid SDK                                        |
| --------------------- | ------------------------------------------------------------- | ------------------------------------------------ |
| **Type**              | Streaming toolkit that embeds in any app                      | Full framework that runs as its own process      |
| **Networks**          | EVM, Solana, Bitcoin, Tron, Hyperliquid                       | EVM, Substrate, Solana, Fuel, Tron, Starknet     |
| **Scaffolding**       | 🟡 Pipes CLI `init` (work in progress)                        | ✅ `sqd init` with templates                      |
| **Event decoding**    | ✅ built in, `commonAbis.erc20` included                       | ✅ generated by `squid-evm-typegen`               |
| **Database targets**  | ✅ ClickHouse, PostgreSQL (Drizzle), BigQuery, Parquet, custom | ✅ PostgreSQL (TypeORM); file stores, BigQuery    |
| **Schema migrations** | ✅ drizzle-kit (Postgres); SQL files (ClickHouse)              | ✅ generated by typeorm-migration                 |
| **GraphQL API**       | ❌ not included                                                | ✅ auto-generated from `schema.graphql`           |
| **Real-time data**    | ✅ unfinalized blocks with automatic fork handling ¹           | ✅ hot blocks (unfinalized blocks), on by default |
| **Observability**     | ✅ Prometheus metrics, progress ETA, OpenTelemetry, Pipes UI   | ✅ Prometheus metrics endpoint                    |
| **SQD Cloud deploy**  | ❌ not supported (self-host on any Node.js host)               | ✅ `sqd deploy`                                   |
| **Maturity**          | ✅ 1.0.0                                                       | ✅ stable, actively maintained                    |

¹ Built-in targets roll back reorganized blocks automatically; the ClickHouse target needs a one-line `onRollback` callback, and fully custom targets implement fork handling themselves.

In short: the Pipes SDK is the lighter, embeddable toolkit, with no GraphQL layer and self-hosted deployment. The Squid SDK is the stable full framework with a generated GraphQL API and one-command SQD Cloud deployment.

For the reasoning behind the Pipes SDK's design, see [Why Pipes SDK?](/en/sdk/pipes-sdk/evm/why-pipes-sdk). Coming from The Graph? See [Squid SDK vs The Graph](/en/sdk/subsquid-vs-thegraph).

## Next steps

<CardGroup cols={3}>
  <Card title="Try the Portal API" icon="network" href="/en/portal/evm/quickstart">
    Run your first query in minutes with plain HTTP
  </Card>

  <Card title="Try the Pipes SDK" icon="text-align-start" href="/en/sdk/pipes-sdk/evm/quickstart">
    Scaffold a pipeline that indexes into your database
  </Card>

  <Card title="Try the Squid SDK" icon="server" href="/en/sdk/squid-sdk/quickstart">
    Build an indexer with a generated GraphQL API
  </Card>

  <Card title="Use Ponder + Portal" icon="bolt" href="/en/sdk/alternative-clients/ponder">
    Back an existing Ponder app with the Portal (beta)
  </Card>
</CardGroup>


## Related topics

- [Build with SQD](/en/sdk/overview.md)
- [Private Portal setup](/en/portal/self-hosting.md)
- [Accessing a Portal](/en/portal/self-hosting/accessing-portal.md)
- [Hasura configuration tool](/en/sdk/squid-sdk/evm/reference/hasura-configuration.md)
- [Squid SDK tips and troubleshooting](/en/sdk/squid-sdk/evm/guides/advanced/tips-and-troubleshooting.md)
