> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/oven-sh/bun/llms.txt
> Use this file to discover all available pages before exploring further.

# Child Processes

> Spawn and manage child processes with Bun.spawn() and Bun.spawnSync(), with full Node.js child_process compatibility.

Bun provides `Bun.spawn()` and `Bun.spawnSync()` for spawning child processes. Both APIs use [`posix_spawn(3)`](https://man7.org/linux/man-pages/man3/posix_spawn.3.html) under the hood, making process spawning 60% faster than Node.js's `child_process` module.

***

## Bun.spawn()

Pass the command as an array of strings. `Bun.spawn()` returns a `Subprocess` object immediately.

```typescript theme={null}
const proc = Bun.spawn(["bun", "--version"]);
const text = await proc.stdout.text();
console.log(text); // => "1.x.x\n"

await proc.exited; // wait for exit, resolves to exit code
```

### Options

Configure the subprocess with a second argument:

```typescript theme={null}
const proc = Bun.spawn(["bun", "--version"], {
  cwd: "./path/to/subdir",           // working directory
  env: { ...process.env, FOO: "bar" }, // environment variables
  onExit(proc, exitCode, signalCode, error) {
    // called when the process exits
  },
});

proc.pid; // process ID of the subprocess
```

***

## Stdin

By default, `stdin` is `null` (no input). Configure it with the `stdin` option:

| Value                    | Description                                   |
| ------------------------ | --------------------------------------------- |
| `null`                   | **Default.** No input to the subprocess.      |
| `"pipe"`                 | Returns a `FileSink` for incremental writing. |
| `"inherit"`              | Inherit stdin from the parent process.        |
| `Bun.file()`             | Read from a file.                             |
| `TypedArray \| DataView` | Use a binary buffer as input.                 |
| `Response`               | Use the response body as input.               |
| `Request`                | Use the request body as input.                |
| `ReadableStream`         | Use a readable stream as input.               |
| `Blob`                   | Use a blob as input.                          |
| `number`                 | Read from a file descriptor.                  |

### Passing a Response as stdin

```typescript theme={null}
const proc = Bun.spawn(["cat"], {
  stdin: await fetch("https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js"),
});

const text = await proc.stdout.text();
console.log(text); // "const input = "hello world".repeat(400); ..."
```

### Writing incrementally with "pipe"

```typescript theme={null}
const proc = Bun.spawn(["cat"], {
  stdin: "pipe",
});

proc.stdin.write("hello");

const enc = new TextEncoder();
proc.stdin.write(enc.encode(" world!"));

proc.stdin.flush(); // send buffered data
proc.stdin.end();   // close the stream
```

### Passing a ReadableStream as stdin

```typescript theme={null}
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue("Hello from ");
    controller.enqueue("ReadableStream!");
    controller.close();
  },
});

const proc = Bun.spawn(["cat"], { stdin: stream, stdout: "pipe" });

const output = await proc.stdout.text();
console.log(output); // "Hello from ReadableStream!"
```

***

## Stdout and stderr

By default, `stdout` is `"pipe"` (a `ReadableStream`) and `stderr` is `"inherit"` (passed through to the parent).

```typescript theme={null}
const proc = Bun.spawn(["bun", "--version"]);
const text = await proc.stdout.text();
console.log(text); // => "1.x.x\n"
```

Configure output streams with the following values:

| Value        | Description                                                             |
| ------------ | ----------------------------------------------------------------------- |
| `"pipe"`     | **Default for stdout.** Exposes a `ReadableStream` on the `Subprocess`. |
| `"inherit"`  | **Default for stderr.** Pass through to the parent process.             |
| `"ignore"`   | Discard the output.                                                     |
| `Bun.file()` | Write to a file.                                                        |
| `number`     | Write to a file descriptor.                                             |

***

## Exit handling

### onExit callback

```typescript theme={null}
const proc = Bun.spawn(["bun", "--version"], {
  onExit(proc, exitCode, signalCode, error) {
    console.log(`Exited with code ${exitCode}`);
  },
});
```

### exited promise

`proc.exited` is a `Promise` that resolves to the exit code when the process finishes:

```typescript theme={null}
const proc = Bun.spawn(["bun", "--version"]);

const code = await proc.exited;
proc.killed;     // boolean — was the process killed?
proc.exitCode;   // null | number
proc.signalCode; // null | "SIGTERM" | "SIGKILL" | ...
```

### Killing a process

```typescript theme={null}
const proc = Bun.spawn(["sleep", "10"]);

proc.kill();           // sends SIGTERM
proc.kill(9);          // sends signal number 9
proc.kill("SIGKILL");  // sends SIGKILL
proc.killed;           // true
```

### Detaching a process

By default, the parent `bun` process waits for all child processes to exit. Use `proc.unref()` to detach the child from the parent's lifetime:

```typescript theme={null}
const proc = Bun.spawn(["some-background-service"]);
proc.unref(); // parent can exit without waiting for this process
```

***

## Timeout and AbortSignal

### Automatic timeout

```typescript theme={null}
// Automatically kill the process after 5 seconds
const proc = Bun.spawn({
  cmd: ["sleep", "10"],
  timeout: 5000, // milliseconds
});

await proc.exited; // resolves after 5 seconds
```

By default, timed-out processes are killed with `SIGTERM`. Use `killSignal` to specify a different signal:

```typescript theme={null}
const proc = Bun.spawn({
  cmd: ["sleep", "10"],
  timeout: 5000,
  killSignal: "SIGKILL",
});
```

### AbortSignal

```typescript theme={null}
const controller = new AbortController();

const proc = Bun.spawn({
  cmd: ["sleep", "100"],
  signal: controller.signal,
});

// Later, abort the process
controller.abort();
```

***

## Resource usage

After a process exits, inspect its resource consumption:

```typescript theme={null}
const proc = Bun.spawn(["bun", "--version"]);
await proc.exited;

const usage = proc.resourceUsage();
console.log(`Max memory: ${usage.maxRSS} bytes`);
console.log(`CPU user time: ${usage.cpuTime.user} µs`);
console.log(`CPU system time: ${usage.cpuTime.system} µs`);
```

***

## Inter-process communication (IPC)

Bun supports a direct IPC channel between two `bun` processes. Specify an `ipc` handler when spawning:

```typescript title="parent.ts" theme={null}
const child = Bun.spawn(["bun", "child.ts"], {
  ipc(message, childProc) {
    console.log("Received from child:", message);
    childProc.send("Hello back from parent");
  },
});

child.send("Hello from parent");
```

In the child process, use `process.send()` and `process.on("message")`:

```typescript title="child.ts" theme={null}
process.send("Hello from child");

process.on("message", message => {
  console.log("Received from parent:", message);
});
```

### Serialization format

The `serialization` option controls how messages are encoded between processes:

| Value        | Description                                                                               |
| ------------ | ----------------------------------------------------------------------------------------- |
| `"advanced"` | **Default.** Uses JSC's `serialize` API — supports everything `structuredClone` supports. |
| `"json"`     | Uses `JSON.stringify` / `JSON.parse`. Required for IPC between Bun and Node.js.           |

### IPC between Bun and Node.js

Set `serialization: "json"` when communicating with a Node.js process:

```javascript bun-node-ipc.js theme={null}
if (typeof Bun !== "undefined") {
  const node = Bun.spawn({
    cmd: ["node", __filename],
    ipc({ message }) {
      console.log(message);
      node.send({ message: "Hey from Bun!" });
      node.kill();
    },
    stdio: ["inherit", "inherit", "inherit"],
    serialization: "json",
  });

  node.send({ message: "Hey Node!" });
} else {
  process.on("message", ({ message }) => {
    console.log(message);
    process.send({ message: "Hey Bun!" });
  });
}
```

To disconnect the IPC channel from the parent:

```typescript theme={null}
childProc.disconnect();
```

***

## Terminal (PTY) support

For interactive terminal applications, spawn a subprocess with a pseudo-terminal attached using the `terminal` option:

```typescript theme={null}
const proc = Bun.spawn(["bash"], {
  terminal: {
    cols: 80,
    rows: 24,
    data(terminal, data) {
      process.stdout.write(data);
    },
  },
});

proc.terminal.write("echo hello\n");

await proc.exited;
proc.terminal.close();
```

When using `terminal`, the subprocess sees `process.stdout.isTTY` as `true`, and `proc.stdin` / `proc.stdout` / `proc.stderr` are `null` — use `proc.terminal` instead.

<Note>
  PTY support is only available on POSIX systems (Linux and macOS). It is not available on Windows.
</Note>

***

## Bun.spawnSync()

`Bun.spawnSync()` is a synchronous, blocking equivalent of `Bun.spawn()`. It returns a `SyncSubprocess` with `stdout` and `stderr` as `Buffer`s.

```typescript theme={null}
const proc = Bun.spawnSync(["echo", "hello"]);

console.log(proc.stdout.toString()); // => "hello\n"
console.log(proc.success);           // => true (exit code 0)
console.log(proc.exitCode);          // => 0
```

<Tip>
  Use `Bun.spawn()` for HTTP servers and long-running applications. Use `Bun.spawnSync()` for CLI tools and scripts where blocking is acceptable.
</Tip>

### maxBuffer

Limit the number of bytes of output before the process is killed:

```typescript theme={null}
const result = Bun.spawnSync({
  cmd: ["yes"],
  maxBuffer: 100, // kill after 100 bytes of output
});
```

***

## Node.js compatibility

Bun is fully compatible with Node.js's `child_process` module:

```typescript theme={null}
import { spawn, spawnSync, execSync, fork } from "child_process";

const child = spawn("ls", ["-la"]);
child.stdout.on("data", data => console.log(data.toString()));

const result = spawnSync("echo", ["hello"]);
console.log(result.stdout.toString()); // => "hello\n"
```

For IPC using `child_process.fork()`, use `process.send()` and `process.on("message")` in the child — the same API as Bun's native IPC.
