Skip to main content
Write pipe output to rotating, finalized-only Parquet files on the local filesystem. Each file is named by the block range it covers (<from>-<to>.parquet) and is immutable once published. The files can be read directly by DuckDB, Spark, Athena, and ClickHouse’s s3() function without an import step.
@dsnp/parquetjs is an optional peer dependency. Install it alongside the SDK:

parquetTarget

ParquetTable: ParquetSettings:

Behavior

  • Finalized-only. A row is written only once its block is at or below the portal’s finalized head, so a reorg never touches a file on disk. On a live (from: 'latest') range, the unfinalized tail is held in memory until it finalizes; a reorg drops the in-memory buffer. See Fork handling for how the finalization watermark is tracked.
  • Constant memory. Rows stream to a temp file that rotates by byte size, so a multi-gigabyte backfill never lands wholly in RAM.
  • Crash-safe. A durable cursor advances only at a checkpoint. On restart, any file above the cursor is dropped and re-fetched.
onData must be a pure function of the batch for finalized blocks (no wall clock or randomness affecting a row’s identity). Recovery re-processes finalized blocks and relies on regenerating identical rows; Parquet has no server-side dedupe.

Example

The output directory holds one sub-directory per table and the state file with the cursor:
parquet-out
transfers
<from>-<to>.parquet
_sqd_parquet_state.erc20-parquet.json
A file name gives the block range the pipe processed for that file, not the lowest and highest block of its rows. Block numbers are zero-padded to 12 digits, so the files sort in block order. The state file name carries the pipe’s source id, or settings.id when set. Query the output directly with DuckDB:
Full runnable example: 17.parquet.example.ts.

JS to Parquet input contract