Learn · Terminal operations

Consume a pipeline

The terminal consumer starts demand, owns completion, and is where unhandled pipeline failures become visible.

Write to a stream

await pipeline.pipeTo(destination)
Open “Consume a pipeline” in the playground

Use pipeTo() for a Node-style writable or Web WritableStream. Its promise settles only when the transfer completes. It rejects on an unhandled record error, source or destination failure, structural format error, or cancellation.

Pull with async iteration

for await (const record of pipeline.toAsyncIterator()) {
  await writeRecord(record)
}

The loop body is the destination. Awaiting it before the next iteration naturally keeps the consumer from running ahead.

Pass a signal when the caller owns cancellation:

for await (const record of pipeline.toAsyncIterator({ signal })) {
  await writeRecord(record)
}

Run side effects

await pipeline.tap(sendMetric).drain()

drain() supplies demand and discards output. Use it for a side-effecting pipeline with no writer. Unlike start(), it waits until completion or failure.

Collect deliberately

const records = await pipeline.toPromise()

Collection keeps the complete result in memory. It is appropriate only when the output is known to fit. For a large or unbounded flow, use a streaming destination instead.

Name ownership

Application code should make the terminal operation easy to find. That line determines who waits, catches fatal errors, and cancels early. A pipeline without an intentional terminal owner is only a description.