node:child_process API Reference

Node.js child_process module — the spawn family and fork with IPC, backed by host process primitives

Node.js child_process module, resolvable via both ESM import and CommonJS require (with or without the node: prefix). The full spawn family is implemented: ChildProcess is an EventEmitter, stdout / stderr are node:stream Readables, and stdin is a Writable.

import { spawn, execSync, fork } from "node:child_process";

const child = spawn("ls", ["-la"]);
child.stdout.on("data", (chunk) => process.stdout.write(chunk));
child.on("exit", (code) => console.log("exited", code));

execSync("echo hi").toString(); // → "hi\n"

Implemented surface

ExportDescription
spawn(command[, args][, options])Launch a process; returns a ChildProcess.
spawnSync(command[, args][, options])Synchronous spawn; returns { pid, status, signal, stdout, stderr, output }.
exec(command[, options][, callback])Run a command through the shell; buffers output.
execSync(command[, options])Synchronous shell execution; returns the captured stdout.
execFile(file[, args][, options][, callback])Launch an executable directly (no shell); buffers output.
execFileSync(file[, args][, options])Synchronous form of execFile.
fork(modulePath[, args][, options])Spawn an Elide child running a module, with an IPC channel.
ChildProcessThe child handle: pid, stdin / stdout / stderr, kill, ref / unref, and the spawn / exit / close / error / disconnect / message events.

fork() and the IPC channel

fork() starts an Elide child process and wires up a message channel: child.send(value), child.on('message', ...), child.disconnect(), child.channel, and child.connected all work, and inside the child the same surface is available on process. Messages are structured values carried over a dedicated channel between parent and child (newline-delimited JSON on an inherited descriptor), so fork behaves like Node’s — including under ahead-of-time preinitialized contexts.

// parent.js
const child = fork("./worker.js");
child.on("message", (m) => console.log("child says", m));
child.send({ n: 41 });

// worker.js
process.on("message", (m) => process.send(m.n + 1));

Spawn backends

Process launch takes one of two paths, chosen automatically:

  • JDK ProcessBuilder — the default for ordinary spawns.
  • Native spawn (Rust, via FFM) — used when the options require what ProcessBuilder cannot express: detached (new session via setsid), uid / gid, argv0, or the extra inherited descriptor that carries the fork() IPC channel.

Both paths behave identically from JavaScript; stdio is delivered over raw file descriptors in either mode, so behavior matches between JVM mode and the native binary.

Sandboxing: --allow-run / --deny-run

Process creation participates in Elide’s sandbox. Two global CLI flags gate it:

  • --allow-run[=<name,...>] — permit spawning (optionally restricted to a list of executable names or paths).
  • --deny-run[=<name,...>] — deny spawning (optionally only for the listed executables).

When process execution is restricted, calls into node:child_process fail with a permission error rather than launching the child.

Not yet supported

  • Windows-specific options (windowsHide, windowsVerbatimArguments) are accepted but have no effect on POSIX hosts.
  • stdio descriptor passing beyond the standard streams and the IPC channel (arbitrary extra fds).

See also