Skip to main content
@subsquid/pipes 1.0 is a major release: every rename is hard — the old names are removed, with no deprecated aliases — so the TypeScript compiler will point you at most of the changes. A few changes are silent, though, and those are called out below. Pick the tab matching the version in your package.json:
  • 0.1.0-beta.* — the previous 0.1.x line. Most existing pipes are here.
  • 1.0.0-alpha.* — the 1.0 preview line. The pipeline structure already matches 1.0; what remains is mostly the naming overhaul that landed late in the alpha series.
The 1.0 line ships under the npm beta tag, so install it explicitly:
The exhaustive step-by-step list (including rarely-used types) lives in the package’s MIGRATION.md.

1. Decoders move into outputs

Portal sources became portal streams, and .pipe(decoder) / .pipeComposite({...}) on the source are gone. Pass decoders through the required outputs option instead:
What was .pipeComposite({ ... }) is now a named record: outputs: { transfers: ..., swaps: ... }. The data shape is unchanged. See Pipe anatomy for the full 1.0 pipe structure.

2. Every stream needs an id

The id shown above is now required: it must be globally unique, stable and non-empty. Targets use it as the cursor key to persist progress, and it scopes log lines and Prometheus labels. Calling .pipeTo() without one throws DefaultPipeIdError (E0001).Because cursors are now keyed by the id (previously a static "stream" key shared by every pipe), the first restart after upgrading migrates your stored cursor:If several pipes shared one offset table under the old default, pin explicit per-target ids before upgrading — see Cursor management.

3. Raw outputs are plain block arrays

If you consume a stream without a decoder, data is now the block array itself — drop the .blocks accessor (data.blocks.map(...)data.map(...)). This also applies inside custom transformers.

4. Renames

Functions:Types:In the runner, createDevRunner is now devRunner and each pipe’s stream field is now handler. In progress callbacks, ProgressEvent data is nested under .progress, and its state reads from/to instead of initial/last.

5. Custom transformers and targets

  • A transformer’s fork hook is renamed forkrollback — it receives the already-resolved safe cursor and must undo internal state above it. See the Transformer reference.
  • A custom target’s contract method is fork(previousBlocks)resolveFork(canonicalBlocks) — it receives the portal’s view of the canonical chain, finds the common ancestor, rolls back above it, and returns the resume cursor. See createTarget and Fork handling.
  • query.build({ transform, fork }) no longer accepts transform options — build the query first, then chain: .build().pipe({ transform, rollback }).

6. ClickHouse target

The onRollback discriminator changed: type: 'offset_check' | 'blockchain_fork'reason: 'recovery' | 'fork', and the context carries safeCursor only (the cursor duplicate is gone). This does not surface as a compile error if you only destructure store — grep for the old values.store.removeAllRows is now engine-aware: cancel rows (sign = -1) on CollapsingMergeTree-family tables, a lightweight DELETE (ClickHouse ≥ 23.3) elsewhere, an explicit error on Distributed tables. See the ClickHouse guide.

7. Parquet target

The TIMESTAMP_MILLIS column type is renamed TIMESTAMP (identical file format — only schemas change). New column types: DATE, JSON, STRUCT, LIST.

8. Observability

  • Prometheus gauges: sqd_current_blocksqd_processed_block, sqd_last_blocksqd_end_block (the value is the end of the indexed range, not the chain head). Update dashboards and alerts.
  • The metrics server now serves GET /preview/transformation (was /exemplars/transformation); the /profiler payload key profilers is now profiles.
  • Upgrade Pipes UI together with the SDK — older UI versions read endpoints that no longer exist.