109

In an online training video I am watching to learn Node, the narrator says that "spawn is better for longer processes involving large amounts of data, whereas execute is better for short bits of data."

Why is this? What is the difference between the child_process spawn and execute functions in Node.js, and when do I know which one to use?

Harrison Cramer
  • 3,792
  • 9
  • 33
  • 61

4 Answers4

127

The main difference is that spawn is more suitable for long-running processes with huge output. That's because spawn streams input/output with a child process. On the other hand, exec buffers output in a small (by default 1MB, 200 KB till v11.x) buffer. exec first spawns a subshell, and then tries to execute your process. To cut a long story short, use spawn in case you need a lot of data streamed from a child process and exec if you need features like shell pipes, redirects or even more than one program at a time.

Some useful links - DZone Hacksparrow

Kunal Kukreja
  • 737
  • 4
  • 18
Vasyl Moskalov
  • 4,242
  • 3
  • 20
  • 28
  • I'm also a beginner of node. I noticed that both `exec` and `spawn` return `ChildProcess` object. The doc says `spawn` streams `stdout` while `exec` buffers it, so I tried this: `cp.stdout.on("data", ...)` where the `cp` was returned by `exec`. It turned out the data was also streaming out piece by piece. I'm a bit confused. – Zhou Nov 22 '20 at 10:11
  • 4
    @Zhou you can use the returned ChildProcess object from `exec` similar to how you would use it from `spawn`, however, it would kinda defeat the purpose of using `exec` as that function abstracts away the need to deal with the streams. But behind the scenes those streams are still present, `exec` just deals with collecting the data from them for you. What you discovered is just that those streams are technically still available to you when using `exec`. However, there's normally no real need for them. – Thomas Watson Jan 12 '21 at 09:43
80
  • child process created by spawn()

    • does not spawn a shell
    • streams the data returned by the child process (data flow is constant)
    • has no data transfer size limit
  • child process created by exec()

    • does spawn a shell in which the passed command is executed
    • buffers the data (waits till the process closes and transfers the data in on chunk)
    • maximum data transfer up to Node.js v.12.x was 200kb (by default), but since Node.js v.12x was increased to 1MB (by default)

-main.js (file)

var {spawn, exec} = require('child_process');

    // 'node' is an executable command (can be executed without a shell) 
    // uses streams to transfer data (spawn.stout)  
var spawn = spawn('node', ['module.js']);     
spawn.stdout.on('data', function(msg){         
    console.log(msg.toString())
});

    // the 'node module.js' runs in the spawned shell 
    // transfered data is handled in the callback function 
var exec = exec('node module.js', function(err, stdout, stderr){
    console.log(stdout);
});

-module.js (basically returns a message every second for 5 seconds than exits)

var interval;
interval = setInterval(function(){
    console.log( 'module data' );
    if(interval._idleStart > 5000) clearInterval(interval);
}, 1000);
  • the spawn() child process returns the message module data every 1 second for 5 seconds, because the data is 'streamed'
  • the exec() child process returns one message only module data module data module data module data module data after 5 seconds (when the process is closed) this is because the data is 'buffered'

NOTE that neither the spawn() nor the exec() child processes are designed for running node modules, this demo is just for showing the difference, (if you want to run node modules as child processes use the fork() method instead)

projektorius96
  • 114
  • 2
  • 10
Pall Arpad
  • 1,625
  • 16
  • 20
  • 7
    As a side note, avoid doing `var spawn = spawn(...)` and `var exec = exec(...)`, as that would overwrite the functions. – Remirror Jun 23 '21 at 13:31
  • ```spawn``` can run a shell, if the option.shell attribute is set accordingly. see: https://nodejs.org/api/child_process.html#child_processspawncommand-args-options – MichaelMoser Mar 21 '23 at 13:33
30

A good place to start is the NodeJS documentation.

For 'spawn' the documentation state:

The child_process.spawn() method spawns a new process using the given command, with command line arguments in args. If omitted, args defaults to an empty array.

While for 'exec':

Spawns a shell then executes the command within that shell, buffering any generated output. The command string passed to the exec function is processed directly by the shell and special characters (vary based on shell) need to be dealt with accordingly.

The main thing appears to be whether you need handle the output of the command or not, which I imagine could be the factor impacting performance (I haven't compared). If you care only about process completion then 'exec' would be your choice. Spawn opens streams for stdout and stderr with ondata events, exec just returns a buffer with stdout and stderr as strings.

Govind Rai
  • 14,406
  • 9
  • 72
  • 83
Andre M
  • 6,649
  • 7
  • 52
  • 93
  • 26
    The last line of this answer should read: if you care only about process completion then 'exec' would be your choice. Spawn opens streams for stdout en stderr with ondata events, exec just returns a buffer with stdout and stderr as strings. – anneb Sep 14 '19 at 11:41
  • 8
    I argue with that "A good place to start is the NodeJS". I just started and couldn't filter out the differences, too big wall of text hit me hard. I read about one, scrolled down and forgot what I read. I know RTFM is King, but FM to get read should be more humane – Marecky Aug 17 '21 at 14:37
  • 3
    Agreed with @Marecky. The nodejs docs are like a dictionary: good references for individual elements, but poorly suited at highlighting the difference between similar ones. – hraban Sep 05 '21 at 14:56
5

A quote from the official docs:

For convenience, the child_process module provides a handful of synchronous and asynchronous alternatives to child_process.spawn() and child_process.spawnSync(). Each of these alternatives are implemented on top of child_process.spawn() or child_process.spawnSync().

Yaroslav
  • 4,543
  • 5
  • 26
  • 36