Stream output
This guide shows you how to handle real-time output from commands, processes, and code execution.
Use streaming when you need:
- Real-time feedback - Show progress as it happens
- Long-running operations - Builds, tests, installations that take time
- Interactive applications - Chat bots, code execution, live demos
- Large output - Process output incrementally instead of all at once
- User experience - Prevent users from waiting with no feedback
Use non-streaming (exec()) for:
- Quick operations - Commands that complete in seconds
- Small output - When output fits easily in memory
- Post-processing - When you need complete output before processing
Use execStream() to get real-time output:
import { getSandbox, parseSSEStream } from "@cloudflare/sandbox";
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
const stream = await sandbox.execStream("npm run build");
for await (const event of parseSSEStream(stream)) {  switch (event.type) {    case "stdout":      console.log(event.data);      break;
    case "stderr":      console.error(event.data);      break;
    case "complete":      console.log("Exit code:", event.exitCode);      break;
    case "error":      console.error("Failed:", event.error);      break;  }}import { getSandbox, parseSSEStream, type ExecEvent } from '@cloudflare/sandbox';
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
const stream = await sandbox.execStream('npm run build');
for await (const event of parseSSEStream<ExecEvent>(stream)) {  switch (event.type) {    case 'stdout':      console.log(event.data);      break;
    case 'stderr':      console.error(event.data);      break;
    case 'complete':      console.log('Exit code:', event.exitCode);      break;
    case 'error':      console.error('Failed:', event.error);      break;  }}Return streaming output to users via Server-Sent Events:
export default {  async fetch(request, env) {    const sandbox = getSandbox(env.Sandbox, "builder");
    const stream = await sandbox.execStream("npm run build");
    return new Response(stream, {      headers: {        "Content-Type": "text/event-stream",        "Cache-Control": "no-cache",      },    });  },};export default {  async fetch(request: Request, env: Env): Promise<Response> {    const sandbox = getSandbox(env.Sandbox, 'builder');
    const stream = await sandbox.execStream('npm run build');
    return new Response(stream, {      headers: {        'Content-Type': 'text/event-stream',        'Cache-Control': 'no-cache'      }    });  }};Client-side consumption:
// Browser JavaScriptconst eventSource = new EventSource("/build");
eventSource.addEventListener("stdout", (event) => {  const data = JSON.parse(event.data);  console.log(data.data);});
eventSource.addEventListener("complete", (event) => {  const data = JSON.parse(event.data);  console.log("Exit code:", data.exitCode);  eventSource.close();});// Browser JavaScriptconst eventSource = new EventSource('/build');
eventSource.addEventListener('stdout', (event) => {  const data = JSON.parse(event.data);  console.log(data.data);});
eventSource.addEventListener('complete', (event) => {  const data = JSON.parse(event.data);  console.log('Exit code:', data.exitCode);  eventSource.close();});Monitor background process output:
import { parseSSEStream } from "@cloudflare/sandbox";
const process = await sandbox.startProcess("node server.js");
const logStream = await sandbox.streamProcessLogs(process.id);
for await (const log of parseSSEStream(logStream)) {  console.log(log.data);
  if (log.data.includes("Server listening")) {    console.log("Server is ready");    break;  }}import { parseSSEStream, type LogEvent } from '@cloudflare/sandbox';
const process = await sandbox.startProcess('node server.js');
const logStream = await sandbox.streamProcessLogs(process.id);
for await (const log of parseSSEStream<LogEvent>(logStream)) {  console.log(log.data);
  if (log.data.includes('Server listening')) {    console.log('Server is ready');    break;  }}Check exit codes and handle stream errors:
const stream = await sandbox.execStream("npm run build");
for await (const event of parseSSEStream(stream)) {  switch (event.type) {    case "stdout":      console.log(event.data);      break;
    case "error":      throw new Error(`Build failed: ${event.error}`);
    case "complete":      if (event.exitCode !== 0) {        throw new Error(`Build failed with exit code ${event.exitCode}`);      }      break;  }}const stream = await sandbox.execStream('npm run build');
for await (const event of parseSSEStream<ExecEvent>(stream)) {  switch (event.type) {    case 'stdout':      console.log(event.data);      break;
    case 'error':      throw new Error(`Build failed: ${event.error}`);
    case 'complete':      if (event.exitCode !== 0) {        throw new Error(`Build failed with exit code ${event.exitCode}`);      }      break;  }}- Always consume streams - Don't let streams hang unconsumed
- Handle all event types - Process stdout, stderr, complete, and error events
- Check exit codes - Non-zero exit codes indicate failure
- Provide feedback - Show progress to users for long operations
- Commands API reference - Complete streaming API
- Execute commands guide - Command execution patterns
- Background processes guide - Process log streaming
- Code Interpreter guide - Stream code execution output
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark