Skip to content
Ilha
Esc
navigateopen⌘Jpreview
On this page

Streams

Paint Effect Streams of views, bridge atoms with Atom.toStream, and use when for per-emission generator bodies.

Streams

Generator components can yield a Stream of views. Compose with Effect (Stream.map, Stream.pipe, …) — Ilha repaints on each emission. SSR takes the first value only; the client keeps listening after mount.

import * as import StreamStream from "effect/Stream";

function* function Status(): Generator<Stream.Stream<View, never, never>, void, unknown>Status() {
  yield import StreamStream.const map: <string, never, never, View>(self: Stream.Stream<string, never, never>, f: (a: string, i: number) => View) => Stream.Stream<View, never, never> (+1 overload)
Transforms the elements of this stream using the supplied function. **Example** (Mapping stream values) ```ts import.meta.vitest import { Effect, Option, Stream } from "effect" const stream = Stream.fromArray([1, 2, 3]).pipe(Stream.map((n, i) => n + i)) await Effect.runPromise(Stream.runCollect(stream)) // => [1, 3, 5] ```
@categorymapping@since2.0.0
map
(
import StreamStream.
const fromIterable: <string>(iterable: Iterable<string>, options?: {
    readonly chunkSize?: number | undefined;
}) => Stream.Stream<string, never, never>
Creates a new `Stream` from an iterable collection of values. **Details** - `chunkSize`: Maximum number of values emitted per chunk. **Example** (Creating a stream from an iterable) ```ts import.meta.vitest import { Effect, Stream } from "effect" const numbers = [1, 2, 3] const program = Effect.gen(function*() { const stream = Stream.fromIterable(numbers) const values = yield* Stream.runCollect(stream) values // => [1, 2, 3] }) await Effect.runPromise(program) ```
@categoryconstructors@since2.0.0
fromIterable
(["idle", "ready"]),
(value: stringvalue) => <IntrinsicElements[string]: anyp>{value: stringvalue}</IntrinsicElements[string]: anyp>, ); }

Async components can return a Stream directly — no generator required.

Atom.toStream

Turn an atom into a change feed with Atom.toStream:

import * as import StreamStream from "effect/Stream";
import * as import AtomAtom from "effect/unstable/reactivity/Atom";
import { const atom: AtomFnatom } from "ilha";

function* function List(): Generator<Stream.Stream<View, never, AtomRegistry>, void, unknown>List() {
  const const items: AtomHandle<string[]>items = atom<string[]>(init: string[] | Atom.Atom<string[]> | Effect<string[], any, any> | Stream.Stream<string[], any, any>): AtomHandle<string[]>atom(["a", "b"]);
  yield import StreamStream.const map: <string[], never, AtomRegistry, View>(self: Stream.Stream<string[], never, AtomRegistry>, f: (a: string[], i: number) => View) => Stream.Stream<View, never, AtomRegistry> (+1 overload)
Transforms the elements of this stream using the supplied function. **Example** (Mapping stream values) ```ts import.meta.vitest import { Effect, Option, Stream } from "effect" const stream = Stream.fromArray([1, 2, 3]).pipe(Stream.map((n, i) => n + i)) await Effect.runPromise(Stream.runCollect(stream)) // => [1, 3, 5] ```
@categorymapping@since2.0.0
map
(import AtomAtom.const toStream: <string[]>(self: Atom.Atom<string[]>) => Stream.Stream<string[], never, AtomRegistry>
Converts an atom into a stream using the `AtomRegistry` service. **Details** The stream emits the atom's current value immediately and then emits subsequent changes until the stream scope is closed.
@categoryconverting@since4.0.0
toStream
(const items: AtomHandle<string[]>items.AtomHandle<string[]>.atom: Atom.Atom<string[]>atom), (list: string[]list) => (
<IntrinsicElements[string]: anyul> {list: string[]list.Array<string>.map<View>(callbackfn: (value: string, index: number, array: string[]) => View, thisArg?: any): View[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => (
<IntrinsicElements[string]: anyli key: stringkey={item: stringitem}>{item: stringitem}</IntrinsicElements[string]: anyli> ))} </IntrinsicElements[string]: anyul> )); }

Use items().map(...) in a sync component for a simple list. Reach for Atom.toStream when a stream pipeline should drive updates (debounce, merge, server feeds).

when

when(stream, body) runs a generator body per emission. A new value interrupts the previous body — stale async work does not paint.

import * as import EffectEffect from "effect/Effect";
import * as import StreamStream from "effect/Stream";
import * as import AtomAtom from "effect/unstable/reactivity/Atom";
import { const atom: AtomFnatom, function when<A, E = never, R = never>(stream: Stream.Stream<A, E, R>, body: (value: A) => Generator<Yielded, View | void, unknown>): Instruction<void, E>when } from "ilha";

function* function Search(): Generator<View, void, any>Search() {
  const const query: AtomHandle<string>query = atom<string>(init: string | Atom.Atom<string> | Effect.Effect<string, any, any> | Stream.Stream<string, any, any>): AtomHandle<string>atom("");
  yield (
    <IntrinsicElements[string]: anyinput
      value: AtomHandle<string>value={const query: AtomHandle<string>query}
      oninput: (e: Event) => voidoninput={(e: Evente: Event) =>
        const query: AtomHandle<string>query.AtomHandle<string>.set(next: string): voidset((e: Evente.Event.currentTarget: EventTarget | null
The **`currentTarget`** read-only property of the Event interface identifies the element to which the event handler has been attached. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/currentTarget) Alias for event.target.
currentTarget
as HTMLInputElement).HTMLInputElement.value: string
The **`value`** property of the HTMLInputElement interface represents the current value of the <input> element as a string. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLInputElement/value)
value
)
} /> ); yield* when<string, never, AtomRegistry>(stream: Stream.Stream<string, never, AtomRegistry>, body: (value: string) => Generator<Yielded, View | void, unknown>): Instruction<void, never>when( import AtomAtom.const toStream: <string>(self: Atom.Atom<string>) => Stream.Stream<string, never, AtomRegistry>
Converts an atom into a stream using the `AtomRegistry` service. **Details** The stream emits the atom's current value immediately and then emits subsequent changes until the stream scope is closed.
@categoryconverting@since4.0.0
toStream
(const query: AtomHandle<string>query.AtomHandle<string>.atom: Atom.Atom<string>atom).Pipeable.pipe<Stream.Stream<string, never, AtomRegistry>, Stream.Stream<string, never, AtomRegistry>>(this: Stream.Stream<string, never, AtomRegistry>, ab: (_: Stream.Stream<string, never, AtomRegistry>) => Stream.Stream<string, never, AtomRegistry>): Stream.Stream<string, never, AtomRegistry> (+21 overloads)pipe(
import StreamStream.const debounce: (duration: Input) => <A, E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<A, E, R> (+1 overload)
Drops earlier elements within the debounce window and emits only the latest element after the pause. **Example** (Debouncing stream elements) ```ts import.meta.vitest import { Duration, Effect, Stream } from "effect" const stream = Stream.make(1, 2, 3).pipe(Stream.debounce(Duration.zero)) const program = Effect.gen(function*() { const values = yield* Stream.runCollect(stream) values // => [ 3 ] }) await Effect.runPromise(program) ```
@categoryrate limiting@since2.0.0
debounce
("200 millis"),
), function* (q: stringq) { if (!q: stringq) { yield <IntrinsicElements[string]: anyp>Type to search</IntrinsicElements[string]: anyp>; return; } const const items: anyitems = yield* import EffectEffect.
const tryPromise: <any, unknown>(options: {
    readonly try: (signal: AbortSignal) => PromiseLike<any>;
    readonly catch: (error: unknown) => unknown;
} | ((signal: AbortSignal) => PromiseLike<any>)) => Effect.Effect<any, unknown, never>
Creates an `Effect` from an asynchronous computation that may throw or reject, mapping failures into the error channel. **When to use** Use when you need to perform asynchronous operations that might fail, such as fetching data from an API, and want thrown exceptions or rejected promises captured as Effect errors. **Details** The promise thunk is evaluated when the effect runs. If it returns a promise that resolves, the resolved value becomes the success value. If the thunk throws before returning a promise, or if the returned promise rejects, the thrown or rejected value is mapped into the error channel. Passing the thunk directly maps failures to {@link Cause.UnknownError } . Passing `{ try, catch }` uses `catch` to map failures to an error of type `E`. The thunk receives an `AbortSignal` that is aborted if the effect is interrupted. The underlying asynchronous operation only stops if it observes that signal. **Gotchas** If `catch` throws while mapping the error, that thrown value is treated as a defect. Return the error value you want in the error channel instead of throwing it. **Example** (Wrapping a fetch request that may fail) ```ts import.meta.vitest import { Effect } from "effect" const getTodo = (id: number) => Effect.tryPromise(() => Promise.resolve({ id, completed: false })) // ┌─── Effect<{ id: number; completed: boolean }, UnknownError, never> // ▼ const program = getTodo(1) await Effect.runPromise(program) // => { id: 1, completed: false } ``` **Example** (Mapping Promise rejections to a tagged error) ```ts import.meta.vitest import { Data, Effect } from "effect" class TodoFetchError extends Data.TaggedError("TodoFetchError")<{ readonly cause: unknown }> {} const getTodo = (id: number) => Effect.tryPromise({ try: () => Promise.reject(`Todo ${id} is unavailable`), // remap the error catch: (cause) => new TodoFetchError({ cause }) }) // ┌─── Effect<never, TodoFetchError, never> // ▼ const program = Effect.flip(getTodo(1)) const error = await Effect.runPromise(program) error._tag // => "TodoFetchError" ```
@see{@link promise} if the effectful computation is asynchronous and does not throw errors.@categoryconstructors@since2.0.0
tryPromise
({
try: (signal: AbortSignal) => PromiseLike<any>try: (signal: AbortSignalsignal) => function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+3 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/fetch)
fetch
(`/api/search?q=${function encodeURIComponent(uriComponent: string | number | boolean): string
Encodes a text string as a valid component of a Uniform Resource Identifier (URI).
@paramuriComponent A value representing an unencoded URI component.
encodeURIComponent
(q: stringq)}`, {
RequestInit.signal?: AbortSignal | null | undefined
An AbortSignal to set request's signal.
signal
,
}).Promise<Response>.then<any, never>(onfulfilled?: ((value: Response) => any) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<any>
Attaches callbacks for the resolution and/or rejection of the Promise.
@paramonfulfilled The callback to execute when the Promise is resolved.@paramonrejected The callback to execute when the Promise is rejected.@returnsA Promise for the completion of which ever callback is executed.
then
((r: Responser) => r: Responser.Body.json(): Promise<any>
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json)
json
()),
catch: (error: unknown) => unknowncatch: (e: unknowne) => e: unknowne, }); yield ( <IntrinsicElements[string]: anyul> {(const items: anyitems as string[]).Array<string>.map<View>(callbackfn: (value: string, index: number, array: string[]) => View, thisArg?: any): View[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((item: stringitem) => (
<IntrinsicElements[string]: anyli key: stringkey={item: stringitem}>{item: stringitem}</IntrinsicElements[string]: anyli> ))} </IntrinsicElements[string]: anyul> ); }, ); }

yield Stream.map(...) is enough for a stream of views. Use when when each emission needs its own async generator.

Generators

Yield Meaning
yield <p>…</p> Paint this view
yield stream Subscribe to a Stream of views
yield* effect Run an Effect (fetch, sleep, Deferred)
yield* when(...) Per-emission body; stale bodies interrupt

Uncaught failures paint an error view.

Side effects

For atom-driven side effects in any component, use watch(). In generators, yield* Stream.runForEach works for finite streams:

import * as import EffectEffect from "effect/Effect";
import * as import StreamStream from "effect/Stream";

function* function Boot(): Generator<string | number | bigint | boolean | Effect.Effect<void, never, never> | VNode | AtomHandle<any> | Stream.Stream<View, any, any> | GeneratorFn | (() => View | void | Promise<View | void>) | Iterable<View> | null | undefined, void, any>Boot() {
  yield* import StreamStream.const runForEach: <number, never, never, void, never, never>(self: Stream.Stream<number, never, never>, f: (a: number) => Effect.Effect<void, never, never>) => Effect.Effect<void, never, never> (+1 overload)
Runs the provided effectful callback for each element of the stream. **Example** (Running an effect for each value) ```ts import.meta.vitest import { Effect, Stream } from "effect" const stream = Stream.make(1, 2, 3) const values: Array<string> = [] const program = Effect.gen(function*() { yield* Stream.runForEach(stream, (n) => Effect.sync(() => values.push(`Processing: ${n}`))) }) await Effect.runPromise(program) values // => ["Processing: 1", "Processing: 2", "Processing: 3"] ```
@categorydestructors@since2.0.0
runForEach
(
import StreamStream.
const fromIterable: <number>(iterable: Iterable<number>, options?: {
    readonly chunkSize?: number | undefined;
}) => Stream.Stream<number, never, never>
Creates a new `Stream` from an iterable collection of values. **Details** - `chunkSize`: Maximum number of values emitted per chunk. **Example** (Creating a stream from an iterable) ```ts import.meta.vitest import { Effect, Stream } from "effect" const numbers = [1, 2, 3] const program = Effect.gen(function*() { const stream = Stream.fromIterable(numbers) const values = yield* Stream.runCollect(stream) values // => [1, 2, 3] }) await Effect.runPromise(program) ```
@categoryconstructors@since2.0.0
fromIterable
([1, 2, 3]),
(n: numbern) => import EffectEffect.const sync: <void>(thunk: LazyArg<void>) => Effect.Effect<void, never, never>
Creates an `Effect` that represents a synchronous side-effectful computation. **When to use** Use when you need to wrap a synchronous side-effectful operation that is not expected to throw. **Details** The provided function is evaluated lazily when the effect runs. **Gotchas** The function must not throw. If it throws, the thrown value is treated as a defect, not as a typed failure. Use `try` when throwing is expected. **Example** (Capturing synchronous logging in an Effect) ```ts import.meta.vitest import { Effect } from "effect" const output: Array<unknown> = [] const log = (message: string) => Effect.sync(() => { void output.push(message) // side effect }) // ┌─── Effect<void, never, never> // ▼ const program = log("Hello, World!") Effect.runSync(program) output // => ["Hello, World!"] ```
@see{@link try_try} for a version that can handle failures.@categoryconstructors@since2.0.0
sync
(() => var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v24.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v24.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v24.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v24.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(n: numbern)),
); yield <IntrinsicElements[string]: anyp>Ready</IntrinsicElements[string]: anyp>; }

Co-locate DOM effects in event handlers when you own the write site.

Deferred

Paint UI, wait for input, then continue:

import * as import DeferredDeferred from "effect/Deferred";
import * as import EffectEffect from "effect/Effect";

function* function Gate(): Generator<string | number | bigint | boolean | Effect.Effect<Deferred.Deferred<string, never>, never, never> | VNode | AtomHandle<any> | Stream<View, any, any> | GeneratorFn | (() => View | void | Promise<View | void>) | Iterable<View> | Effect.Effect<string, never, never> | null | undefined, void, any>Gate() {
  const const deferred: Deferred.Deferred<string, never>deferred = yield* import DeferredDeferred.const make: <string, never>() => Effect.Effect<Deferred.Deferred<string, never>, never, never>
Creates a new `Deferred`. **When to use** Use to allocate an empty `Deferred` inside an `Effect` workflow. **Example** (Creating a Deferred) ```ts import.meta.vitest import { Deferred, Effect } from "effect" const program = Effect.gen(function*() { const deferred = yield* Deferred.make<number>() yield* Deferred.succeed(deferred, 42) return yield* Deferred.await(deferred) }) await Effect.runPromise(program) // => 42 ```
@categoryconstructors@since2.0.0
make
<string>();
yield ( <IntrinsicElements[string]: anybutton type: stringtype="button" onclick: () => booleanonclick={() => import EffectEffect.const runSync: <boolean, never>(effect: Effect.Effect<boolean, never, never>) => boolean
Executes an effect synchronously and returns its success value. **When to use** Use when you need to execute an effect that is guaranteed to complete synchronously. **Details** If the effect fails, dies, is interrupted, or performs asynchronous work, `runSync` throws a `FiberFailure` instead of returning a value. Use `runSyncExit` when you want the failure captured as an `Exit`. **Example** (Running a synchronous effect) ```ts import.meta.vitest import { Effect } from "effect" const output: Array<unknown> = [] const program = Effect.sync(() => { void output.push("Hello, World!") return 1 }) const result = Effect.runSync(program) void output.push(result) output // => ["Hello, World!", 1] ``` **Example** (Throwing for failed or async effects) ```ts import.meta.vitest import { Effect } from "effect" const output: Array<unknown> = [] try { // Attempt to run an effect that fails Effect.runSync(Effect.fail("my error")) } catch (e) { void output.push("failed effect") } try { // Attempt to run an effect that involves async work Effect.runSync(Effect.promise(() => Promise.resolve(1))) } catch (e) { void output.push("async effect") } output // => ["failed effect", "async effect"] ```
@see{@link runSyncExit} for a version that returns an `Exit` type instead of throwing an error.@categoryrunning@since2.0.0
runSync
(import DeferredDeferred.const succeed: <string, never>(self: Deferred.Deferred<string, never>, value: string) => Effect.Effect<boolean> (+1 overload)
Attempts to complete the `Deferred` with the specified value. **When to use** Use to complete a `Deferred` with a successful value. **Details** Fibers waiting on the `Deferred` receive the value only if this call completes it. The returned effect succeeds with `true` when this call completed the `Deferred`, or `false` if it was already completed. **Example** (Completing a Deferred with a value) ```ts import.meta.vitest import { Deferred, Effect } from "effect" const program = Effect.gen(function*() { const deferred = yield* Deferred.make<number>() yield* Deferred.succeed(deferred, 42) return yield* Deferred.await(deferred) }) await Effect.runPromise(program) // => 42 ```
@categorycompletion@since2.0.0
succeed
(const deferred: Deferred.Deferred<string, never>deferred, "Ada"))
} > Continue </IntrinsicElements[string]: anybutton> ); const const name: stringname = yield* import DeferredDeferred.
await<string, never>(self: Deferred.Deferred<string, never>): Effect.Effect<string, never, never>
export await
Retrieves the value of the `Deferred`, suspending the fiber running the workflow until the result is available. **When to use** Use to wait for a `Deferred` to be completed and resume with its success, failure, defect, or interruption. **Details** Awaiters observe the completion effect stored in the `Deferred`. **Example** (Awaiting a Deferred value) ```ts import.meta.vitest import { Deferred, Effect } from "effect" const program = Effect.gen(function*() { const deferred = yield* Deferred.make<number>() yield* Deferred.succeed(deferred, 42) return yield* Deferred.await(deferred) }) await Effect.runPromise(program) // => 42 ```
@see{@link complete} for completing from an effect and memoizing its result@see{@link completeWith} for completing with an effect directly@categorygetters@since2.0.0
await
(const deferred: Deferred.Deferred<string, never>deferred);
yield <IntrinsicElements[string]: anyp>Hello, {const name: stringname}</IntrinsicElements[string]: anyp>; }

Server feeds

Map a server stream to JSX with Stream.fromAsyncIterable. SSR serializes the first value; the client resumes the feed. See Server islands and PubSub state.

Was this page helpful?