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
| Export | Description |
|---|---|
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. |
ChildProcess | The 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
ProcessBuildercannot express:detached(new session viasetsid),uid/gid,argv0, or the extra inherited descriptor that carries thefork()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. stdiodescriptor passing beyond the standard streams and the IPC channel (arbitrary extra fds).
See also
- Process primitives (host-internal) — the
process.hostlayer that backs this module. - Node.js upstream: https://nodejs.org/api/child_process.html