Lesson 29 of 50 – Child Processes

58% Completed
58%

Child Processes in Node.js

The Child Process module allows Node.js applications to start and communicate with other processes. It is useful for running system commands, executing separate programs, and handling tasks outside the main JavaScript process.

Remember: Child processes run separately from the parent Node.js process. They can help isolate work, but creating a child process does not automatically make every task faster.

1. What Is a Child Process?

A child process is a separate operating-system process started by another process. In Node.js, the built-in child_process module provides methods for creating child processes.

Common uses include:

  • Running command-line tools.
  • Executing another program or script.
  • Automating system tasks.
  • Running external utilities.
  • Separating certain CPU-intensive tasks from the main process.
Importing the Child Process Module
const { exec } = require("child_process");

console.log("Child Process module is ready");
Output:
Child Process module is ready

The child_process module is built into Node.js, so no additional package installation is required.

2. Types of Child Process Methods

Node.js provides several ways to start child processes. The most common methods are listed below.

Method Purpose Typical Use
exec() Runs a command in a shell and collects its output. Short commands with limited output.
execFile() Runs an executable directly without a shell by default. Executing a known program.
spawn() Starts a process with streaming input and output. Commands that produce ongoing output.
fork() Starts another Node.js process with an IPC channel. Communicating between Node.js processes.

3. Using exec()

The exec() method runs a command in a shell and collects its output. When the command completes, its callback receives an error, standard output, and standard error.

Example: Running a Simple Command
const { exec } = require("child_process");

exec("node --version", function(error, stdout, stderr) {
    if (error) {
        console.log("Error:", error.message);
        return;
    }

    if (stderr) {
        console.log("Standard error:", stderr);
    }

    console.log("Node.js version:", stdout.trim());
});
Example Output:
Node.js version: v22.0.0

The displayed version depends on the Node.js version installed on your computer.

Security warning: Avoid passing untrusted user input into shell commands executed with exec(). It can lead to command injection. Prefer execFile() or spawn() with a fixed executable and separate arguments when appropriate.

4. Using execFile()

The execFile() method executes a program directly without using a shell by default. Arguments are supplied separately, which is often safer than building a shell command string.

Example: Running Node.js Directly
const { execFile } = require("child_process");

execFile(
    process.execPath,
    ["--version"],
    function(error, stdout, stderr) {
        if (error) {
            console.log("Error:", error.message);
            return;
        }

        console.log("Version:", stdout.trim());
    }
);
Example Output:
Version: v22.0.0

process.execPath provides the path to the currently running Node.js executable. The version shown depends on your installation.

5. Using spawn()

The spawn() method starts a child process and exposes its standard output and standard error as streams. This is useful when a command produces output over time.

Example: Streaming Command Output
const { spawn } = require("child_process");

const child = spawn(
    process.execPath,
    ["-e", "console.log('Hello from child process')"]
);

child.stdout.on("data", function(data) {
    console.log("Output:", data.toString().trim());
});

child.stderr.on("data", function(data) {
    console.log("Error output:", data.toString());
});

child.on("error", function(error) {
    console.log("Failed to start:", error.message);
});

child.on("close", function(code) {
    console.log("Child process closed with code:", code);
});
Example Output:
Output: Hello from child process
Child process closed with code: 0

The close event occurs after the process has ended and its standard I/O streams have closed. A code of 0 usually indicates successful completion.

6. Using fork()

The fork() method is designed for starting another Node.js process. It creates an inter-process communication (IPC) channel so the parent and child can send messages to each other.

Example: Create a Child File

Create a file named child.js:

process.on("message", function(message) {
    console.log("Child received:", message);

    if (process.send) {
        process.send("Hello from child.js");
    }
});

Now create parent.js in the same folder:

const { fork } = require("child_process");

const child = fork("./child.js");

child.on("message", function(message) {
    console.log("Parent received:", message);
    child.disconnect();
});

child.on("error", function(error) {
    console.log("Child error:", error.message);
});

child.send("Hello from parent.js");
Example Output:
Child received: Hello from parent.js
Parent received: Hello from child.js

The parent sends a message to the child, and the child replies using process.send().

7. Handling Child Process Errors

A child process can fail to start, exit with a nonzero code, or produce errors. You should handle process events and inspect the exit status when needed.

Example: Handling Process Events
const { spawn } = require("child_process");

const child = spawn(
    process.execPath,
    ["-e", "process.exit(1)"]
);

child.on("error", function(error) {
    console.log("Failed to start:", error.message);
});

child.on("close", function(code, signal) {
    if (code !== 0) {
        console.log("Child process failed.");
        console.log("Exit code:", code);
    } else {
        console.log("Child process completed successfully.");
    }
});
Output:
Child process failed.
Exit code: 1

The child deliberately exits with code 1 in this example. A nonzero exit code usually indicates that the command did not complete successfully.

8. Difference Between exec(), spawn(), and fork()

Feature exec() spawn() fork()
Shell by default Yes No No shell command
Output handling Collected by callback Streams IPC and standard streams
Designed for Shell commands Programs and commands Node.js scripts
IPC messaging Not by default Not by default Yes

9. When Should You Use Child Processes?

Practical Uses
  • Running a system utility from a Node.js application.
  • Executing command-line tools during automation.
  • Running another Node.js script as a separate process.
  • Handling a command that produces a large amount of output.
  • Isolating work that needs a separate operating-system process.
Best practice: Use fixed executable paths and pass arguments separately whenever possible. Validate inputs, handle process errors, and avoid running commands with unnecessary privileges.

10. Practical Assignment

Practice these programs:
  1. Run node --version using exec().
  2. Run the Node.js executable using execFile().
  3. Use spawn() to execute a small Node.js script.
  4. Create parent.js and child.js using fork().
  5. Send a message from the parent to the child process.
  6. Handle a child process that exits with a nonzero code.
  7. Compare exec(), execFile(), spawn(), and fork().

Test Your Knowledge – Child Processes

Select the correct answer for each question.

1. Which module is used to create child processes in Node.js?
2. Which method is designed to start another Node.js process with IPC messaging?
3. Which method exposes a child process's output through streams?