What channels are
Channels are stream pipes between iii workers. They let one function write bytes while another function reads those bytes in real time, even when the functions run in different processes or languages.The model
The key idea is that refs travel through regular function calls, but the data itself travels over
the channel.
Why channels exist
Function invocations are JSON messages. That is perfect for structured events and command payloads, but it is the wrong approach for large files, media, streaming responses (agents, chats), and long-running partial output. Channels split coordination from data transfer:- A function call coordinates the work.
- A channel carries the stream.
- The engine tracks tracing and routing.
Runtime flow
The producer creates a channel and passesreaderRef to the consumer. Node and Python materialize
that ref into a live reader before the handler runs. Rust receives the ref as JSON and constructs a
ChannelReader from it. The producer writes chunks into its local writer, and the consumer reads
those chunks from its local reader.
Backpressure and lifecycle
Channel streams connect lazily. Creating a channel allocates refs, but the WebSocket stream connects when one side starts reading or writing. Backpressure is handled by the SDK stream implementation so writers can pause when readers cannot keep up. When the writer closes, the reader receives the stream end, so a writer that fails must not close. If a writer that has connected stops without closing, the reader gets the data already sent and then an error instead of the end. A crash or a lost connection does this on its own. A writer that fails on its own error aborts on purpose: in Node callwriter.stream.destroy() with no argument, and in
Rust drop the writer without calling close(). A Go Close after a failed Write aborts too. Go,
Python and browser writers have no other abort call: a writer left open, in any SDK, keeps the
reader waiting until its socket goes away, at the latest when its process or page exits. A writer
whose socket never opened never reached the engine, so the reader is not told: check the producer’s
result too. That is a writer that failed before its first write or, in Node, right after one, while
its socket was still connecting. When a worker disconnects, its channel connections close with it.
Channel ownership
A channel belongs to the worker that calledengine::channels::create (for example through
worker.createChannel()). When that worker disconnects, the engine releases the channel:
- Ends that no worker has attached yet are dropped. A later attempt to attach with that ref fails
with HTTP
404. - A reader already waiting for a writer that never attached gets an error, not the end of the stream.
- Streams with both ends already attached keep running until they complete.
writerRef or readerRef to another worker, the creating
worker must stay connected until the other worker attaches to its end.
Releasing a channel
The engine releases a channel as soon as either side leaves:- When the reader finishes or disconnects, the engine removes the channel. An end that was never attached goes with it.
- When the reader is gone, the engine closes an attached writer right away, even if the writer is idle, instead of waiting for its next write.