# Event stream
URL: /docs/core/concepts/event-stream

How ExecHandle streams stdout from the sandbox in real time — pipe, async generator, and await.



`sb.exec()` and `sb.execCode()` both return an `ExecHandle`. Under the hood, execd sends execution output as an SSE stream. `ExecHandle` wraps that stream and exposes three consumption modes.

## Modes [#modes]

### Pipe [#pipe]

Send stdout directly to any writable with a `write(chunk: string)` method:

```ts
await sb.exec("npm run build").pipe(process.stdout);
await sb.exec("npm test").pipe(process.stderr);
```

This is the most common mode. Output flows in real time as the command runs.

### Async generator [#async-generator]

Iterate stdout chunks one at a time:

```ts
for await (const chunk of sb.exec("npm run build").stdout()) {
  process.stdout.write(chunk);
  // or process each chunk (e.g. parse log lines)
}
```

Use this when you want to inspect or transform output as it arrives.

### Await [#await]

Await the handle directly to get the full result after the command completes:

```ts
const { stdout, stderr, exitCode } = await sb.exec("node --version");
```

This buffers all stdout in memory and resolves once the command exits. Use when you need the full output as a string.

### result() [#result]

`.result()` is an explicit promise form that resolves to `{ stdout, stderr, exitCode }`:

```ts
const handle = sb.exec("npm test");
// ... do something else ...
const { exitCode } = await handle.result();
```

## ExecResult type [#execresult-type]

```ts
interface ExecResult {
  stdout: string; // full stdout as a string
  stderr: string; // full stderr as a string
  exitCode: number; // process exit code
}
```

## Strict mode [#strict-mode]

By default, `exec()` throws `CommandError` if the exit code is non-zero (strict mode). Pass `{ strict: false }` to get the `ExecResult` instead:

```ts
const { exitCode } = await sb.exec("test -f package.json", { strict: false });
if (exitCode !== 0) {
  console.log("no package.json");
}
```

## What gets streamed [#what-gets-streamed]

Only stdout is streamed via `pipe()` and the `stdout()` generator. Stderr is buffered separately and available via `(await handle).stderr` or `.result()`.

The underlying SSE stream from execd also carries exit code information, which `ExecHandle` uses to populate `exitCode` in the result.
