How to Configure the Exec Runtime for Streaming Output as Server-Sent Events

Set sse: true in the ExecOptions when calling workspace.runtime.exec() to stream command output as Server-Sent Events, returning an async iterator that yields real-time stdout and stderr chunks instead of buffering the complete result.

The cloudflare/computer repository provides a Durable Object-based compute platform for executing arbitrary commands in the cloud. When you need real-time visibility into long-running processes, you can configure the exec runtime to stream output as Server-Sent Events (SSE) rather than waiting for process completion.

Understanding the SSE Configuration Options

The streaming behavior is controlled through the ExecOptions interface defined in packages/computerd/src/exec/types.ts. This configuration object accepts an sse boolean flag that, when set to true, instructs the runtime to establish an SSE-compatible connection.

According to the source code, the sse option (referred to as stream: true in earlier versions of the codebase) modifies how the exec runner handles the command's output buffers. Instead of aggregating stdout and stderr into a single response object, the runtime immediately flushes each line of output as an individual SSE message.

Enabling SSE Streaming in Your Exec Call

To configure streaming, pass the sse flag alongside your command and any other runtime options such as backend, cwd, or timeoutMs.

In packages/computer/src/runtime.ts, the high-level façade exposes workspace.runtime.exec(), which forwards these options to the underlying runner in packages/computerd/src/exec/runner.ts.

// Server-side example (Durable Object)
const handle = await workspace.runtime.exec('tail -f /var/log/app.log', {
  backend: 'container',   // Specify your compute backend
  sse: true,               // Enable Server-Sent Events streaming
  timeoutMs: 60_000,       // Optional: timeout in milliseconds
});

When sse: true is specified, the returned handle implements an async iterator that yields objects conforming to the streaming protocol.

Consuming the SSE Stream

The exec runtime provides two primary patterns for consuming streamed output: server-side iteration via the async iterator protocol, or client-side consumption using the browser's native EventSource API.

Server-Side Async Iterator

As implemented in the runtime façade, the returned handle yields chunks with a specific structure containing the stream type and data payload.

for await (const chunk of handle) {
  if (chunk.type === 'stdout') {
    console.log('STDOUT:', chunk.data);
  } else if (chunk.type === 'stderr') {
    console.error('STDERR:', chunk.data);
  }
}

Each chunk is an object with:

  • type: Either 'stdout' or 'stderr'
  • data: A string containing the line or chunk of output

Client-Side EventSource

Browser clients can connect to an endpoint that proxies the exec call. The runtime generates an SSE-compatible response that can be consumed via EventSource.

// Client-side example
const url = 'https://your-worker.dev/exec?command=tail+-f+log.txt&sse=1';
const evtSource = new EventSource(url);

evtSource.addEventListener('stdout', (e) => {
  console.log('Output:', e.data);
});

evtSource.addEventListener('stderr', (e) => {
  console.error('Error:', e.data);
});

evtSource.onerror = (err) => {
  console.error('SSE Connection Error:', err);
};

The runner.ts implementation ensures that each line of output is properly formatted as an SSE message with appropriate event types and data fields.

Implementation Details in the Source Code

The streaming functionality is distributed across three key modules in the cloudflare/computer repository:

File Purpose
packages/computerd/src/exec/types.ts Defines the ExecOptions interface including the sse: boolean flag
packages/computerd/src/exec/runner.ts Implements the runtime logic that checks options.sse and constructs the SSE-compatible response stream
packages/computer/src/runtime.ts Provides the high-level workspace.runtime.exec() façade that returns the async iterator when SSE is enabled
examples/tutorial/worker-configuration.d.ts Contains documentation comments referencing SSE streaming capabilities

The runner.ts module specifically handles the branch between buffered execution and streaming execution. When options.sse is truthy, it bypasses the standard buffer collection and instead pipes the process streams through an SSE encoder.

Summary

  • Enable streaming by setting sse: true in the ExecOptions object passed to workspace.runtime.exec()
  • Server-side consumption uses the async iterator pattern that yields { type, data } objects for each stdout and stderr chunk
  • Client-side consumption works with the native EventSource API for browser-based real-time log viewing
  • Compatibility exists with other exec options including backend, cwd, and timeoutMs
  • Source implementation resides in packages/computerd/src/exec/runner.ts with type definitions in packages/computerd/src/exec/types.ts

Frequently Asked Questions

What is the difference between sse: true and stream: true?

According to the source analysis, sse: true is the current configuration flag for enabling Server-Sent Events streaming. The stream: true option was used in earlier versions of the codebase but has been superseded by the explicit sse boolean flag in the ExecOptions interface.

Can I combine SSE streaming with other exec options?

Yes. The sse flag operates independently of other configuration parameters. You can combine sse: true with backend: 'container', custom cwd paths, and timeoutMs limits without affecting the streaming behavior, as validated in packages/computerd/src/exec/runner.ts.

What data format does the async iterator yield?

Each iteration yields a JavaScript object with two properties: type (a string equal to either 'stdout' or 'stderr') and data (a string containing the output line or chunk). This structure is consistent across both the server-side iterator and the SSE event data payload.

How do I handle reconnection for long-running SSE streams?

The EventSource API automatically handles HTTP connection reconnections with exponential backoff. For process-level timeouts, configure the timeoutMs option in ExecOptions to prevent indefinite execution. The runtime will close the SSE connection gracefully when the process exits or times out.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →