You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Learn the different ways to run a stream and collect its results: runCollect, runForEach, runDrain, and more.
tags
stream
run
collect
consume
getting-started
rule
description
Choose the right Stream.run* method based on what you need from the results.
author
PaulJPhilp
related
stream-hello-world
stream-vs-effect
lessonOrder
1
Guideline
Streams are lazy - nothing happens until you run them. Choose your run method based on what you need: all results, per-item effects, or just completion.
Rationale
Effect provides several ways to consume a stream, each optimized for different use cases:
Method
Returns
Use When
runCollect
Chunk<A>
Need all results in memory
runForEach
void
Process each item for side effects
runDrain
void
Run for side effects, ignore values
runHead
Option<A>
Only need first value
runLast
Option<A>
Only need last value
runFold
S
Accumulate into single result
Good Example
import{Effect,Stream,Option}from"effect"constnumbers=Stream.make(1,2,3,4,5)// ============================================// runCollect - Get all results as a Chunk// ============================================constcollectAll=numbers.pipe(Stream.map((n)=>n*10),Stream.runCollect)Effect.runPromise(collectAll).then((chunk)=>{console.log([...chunk])// [10, 20, 30, 40, 50]})// ============================================// runForEach - Process each item// ============================================constprocessEach=numbers.pipe(Stream.runForEach((n)=>Effect.log(`Processing: ${n}`)))Effect.runPromise(processEach)// Logs: Processing: 1, Processing: 2, etc.// ============================================// runDrain - Run for side effects only// ============================================constwithSideEffects=numbers.pipe(Stream.tap((n)=>Effect.log(`Saw: ${n}`)),Stream.runDrain// Discard values, just run)// ============================================// runHead - Get first value only// ============================================constgetFirst=numbers.pipe(Stream.runHead)Effect.runPromise(getFirst).then((option)=>{if(Option.isSome(option)){console.log(`First: ${option.value}`)// First: 1}})// ============================================// runLast - Get last value only// ============================================constgetLast=numbers.pipe(Stream.runLast)Effect.runPromise(getLast).then((option)=>{if(Option.isSome(option)){console.log(`Last: ${option.value}`)// Last: 5}})// ============================================// runFold - Accumulate into single result// ============================================constsum=numbers.pipe(Stream.runFold(0,(acc,n)=>acc+n))Effect.runPromise(sum).then((total)=>{console.log(`Sum: ${total}`)// Sum: 15})// ============================================// runCount - Count elements// ============================================constcount=numbers.pipe(Stream.runCount)Effect.runPromise(count).then((n)=>{console.log(`Count: ${n}`)// Count: 5})
Choosing the Right Method
What do you need from the stream?
├── All values → runCollect
├── Process each with side effects → runForEach
├── Just run it (ignore values) → runDrain
├── Only first value → runHead
├── Only last value → runLast
├── Accumulate to one result → runFold
└── Count elements → runCount
Memory Considerations
runCollect loads ALL values into memory - use only for bounded streams
runForEach processes one at a time - memory efficient