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

# Portal stream

> API reference for Solana portal streams

The portal stream connects to SQD Portal and streams blockchain data to your pipeline. It's the starting point for all Pipes SDK data flows.

## solanaPortalStream

Create a portal stream for Solana chains.

```ts theme={"system"}
solanaPortalStream(config: SolanaPortalStreamConfig): PortalStream
```

**Parameters:**

* `id`: (required) Pipeline ID. Must be unique within any infra shared with other pipelines (DB, logging sinks etc).

* `portal`: (required) Portal API URL or config object.
  * String: `"https://portal.sqd.dev/datasets/ethereum-mainnet"`
  * Object with the following fields:

    | Field | Default | Description |
    | - | - | - |
    | `url` | required | Portal dataset URL. |
    | `finalized` | `false` | When `true`, the stream consists of finalized blocks only and none of the [fork handling machinery](../../guides/architecture-deep-dives/fork-handling) is required. |
    | `http` | | Custom `HttpClient` instance or HTTP client options. |
    | `maxBytes` | `10_485_760` (10 MB) | Maximum number of bytes to buffer before flushing a batch. |
    | `maxIdleTimeMs` | `300` | Maximum time (ms) between stream data before the buffered batch is returned. |
    | `maxWaitTimeMs` | `5000` | Maximum time (ms) to wait before the buffered batch is returned. |
    | `headPollIntervalMs` | `0` | Interval (ms) for polling the chain head. |

* `outputs`: (required) A single query-transformers chain combo or record of named outputs.

* `cache`: (optional) Portal cache instance. If supplied, saves portal responses locally and reuses them when the pipeline re-runs.

* `logger`: (optional) A pino-compatible `Logger` instance or a log level string. Accepted level values: `'fatal'`, `'error'`, `'warn'`, `'info'`, `'debug'`, `'trace'`, `'silent'`, `false`, `null`. Passing `false` or `null` silences all log output. When omitted, a default console logger is used.

* `metrics`: (optional) `metricsServer()` instance for exposing Prometheus metrics.

* `progress`: (optional) Options for progress tracking: `{ interval?: number, onProgress?, onStart? }`. `interval` defaults to 5000 ms.

* `profiler`: (optional) Enable the built-in per-batch profiler (`boolean`), or pass span hooks such as [`opentelemetryProfiler()`](../../guides/advanced-topics/tracing). See [Profiling](../../guides/advanced-topics/profiling).

**Example:**

```ts theme={"system"}
import { solanaInstructionDecoder, solanaPortalStream } from "@subsquid/pipes/solana";
import { portalSqliteCache } from "@subsquid/pipes/portal-cache/node";
import * as orcaWhirlpool from "./abi/orca_whirlpool/index.js";

const stream = solanaPortalStream({
  id: "orca-swaps",
  portal: "https://portal.sqd.dev/datasets/solana-mainnet",
  outputs: solanaInstructionDecoder({
    range: { from: 200000000 },
    programId: orcaWhirlpool.programId,
    instructions: { swap: orcaWhirlpool.instructions.swap },
  }),
  cache: portalSqliteCache({ path: "./cache.sqlite" }),
});
```

### Finalized Blocks

You can configure the stream to only receive finalized blocks:

```ts theme={"system"}
const stream = solanaPortalStream({
  portal: {
    finalized: true,
    url: 'https://portal.sqd.dev/datasets/solana-mainnet'
  }
});
```

Using finalized blocks eliminates the need for rollback handlers in your targets, simplifying the logic of your pipeline.

## Pipe methods

### pipe()

Chain a single [whole-pipe transformer](./transformer) to the stream.

```ts theme={"system"}
stream.pipe(transformer)
```

The returned value behaves exactly as the stream.

See also: [Stateful transformers](../../guides/advanced-topics/stateful-transforms).

### pipeTo()

Connect the pipeline to a [target](./target).

```ts theme={"system"}
stream.pipeTo(target)
```

This is a terminal operation: you cannot continue piping after calling this method.

If you want your stream to resume on restarts and properly handle unfinalized data, make sure that the target [manages cursors](../../guides/architecture-deep-dives/cursor-management) and [handles forks](../../guides/architecture-deep-dives/fork-handling) correctly.

<h3 id="symboliterator">
  \*[Symbol.asyncIterator]()
</h3>

Use the pipeline as an async iterator:

```ts theme={"system"}
for await (const { data } of stream) {
  // ... do something with data ...
}
```

On blockchain forks this will throw `ForkException`s - see [Fork handling](../../guides/architecture-deep-dives/fork-handling).


## Related topics

- [Portal stream](/en/sdk/pipes-sdk/evm/reference/basic-components/source.md)
- [EVM Portal stream](/en/sdk/squid-sdk/evm/reference/evm-stream.md)
- [Tron portal stream](/en/sdk/pipes-sdk/tron/reference/basic-components/source.md)
- [Bitcoin portal stream](/en/sdk/pipes-sdk/bitcoin/reference/basic-components/source.md)
- [Hyperliquid fills portal stream](/en/sdk/pipes-sdk/hyperliquid/reference/basic-components/source.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.