Skip to main content
Concepts

Streams

Create a stream, pick its format, and decide when it goes away.

A stream is an append-only log at its own URL. Writers add to the end, and every reader sees the same messages in the same order.

These pages follow one example: an AI agent streams its reply into chat/session-1, and a browser shows it as it arrives.

Agentwrites the replychat/session-1Browsershows the replywriteread

Create a stream

Pick any path. Slashes are fine, and there is nothing to register first.

import { DurableStream } from "@durable-streams/client";

// One stream per chat session
const stream = await DurableStream.create({
	url: "http://127.0.0.1:8642/durable-streams/v1/stream/chat/session-1",
	contentType: "application/json",
	// Delete the stream after a day with no reads or writes
	ttlSeconds: 86400,
});

console.log("created", stream.url);

Creating the same stream twice is safe. Creating it again with different settings returns 409 Conflict.

Choose JSON or bytes

The content type is set at creation and never changes.

  • application/json: each append is one message, and reads return a JSON array. Use it for chat, events, and agent output.
  • Anything else, such as text/plain or application/octet-stream: one continuous run of bytes. Frame messages yourself, for example one JSON object per line.

Clean up automatically

Set one of these when you create the stream, or neither to keep it until you delete it:

  • ttlSeconds: delete after this many seconds with no reads or writes. An active stream never expires.
  • expiresAt: delete at a fixed time, such as 2027-01-01T00:00:00Z.

To delete a stream now, call stream.delete().

On Rivet, each stream is its own Rivet Actor, so streams scale independently and sleep when no one is using them.

Next steps

  • Writing: append the agent’s reply and finish it.
  • Reading: load what is already there.