$ npm install nano-spawn
Tiny process execution for humans — a better
child_process
No dependencies. Small package size:
Despite the small size, this is packed with some essential features:
npx
.stdin
input to the subprocess.stdin
/stdout
/stderr
.For additional features, please check out Execa.
npm install nano-spawn
One of the maintainers @ehmicky is looking for a remote full-time position. Specialized in Node.js back-ends and CLIs, he led Netlify Build, Plugins and Configuration for 2.5 years. Feel free to contact him on his website or on LinkedIn!
import spawn from 'nano-spawn';
const result = await spawn('echo', ['🦄']);
console.log(result.output);
//=> '🦄'
for await (const line of spawn('ls', ['--oneline'])) {
console.log(line);
}
//=> index.d.ts
//=> index.js
//=> …
const result = await spawn('npm', ['run', 'build'])
.pipe('sort')
.pipe('head', ['-n', '2']);
file
: string
arguments
: string[]
options
: Options
Returns: Subprocess
Executes a command using file ...arguments
.
This has the same syntax as child_process.spawn()
.
If file
is 'node'
, the current Node.js version and flags are inherited.
All child_process.spawn()
options can be passed to spawn()
.
Type: object
Default: {}
Override specific environment variables. Other environment variables are inherited from the current process (process.env
).
Type: boolean
Default: false
Allows executing binaries installed locally with npm
(or yarn
, etc.).
Type: string | number | Stream | {string: string}
Subprocess's standard input/output/error.
All values supported by node:child_process
are available. The most common ones are:
'pipe'
(default value): returns the output using result.stdout
, result.stderr
and result.output
.'inherit'
: uses the current process's input/output. This is useful when running in a terminal.'ignore'
: discards the input/output.Stream
: redirects the input/output from/to a stream. For example, fs.createReadStream()
/fs.createWriteStream()
can be used, once the stream's open
event has been emitted.{string: '...'}
: passes a string as input to stdin
.Subprocess started by spawn()
.
Returns: Result
Throws: SubprocessError
A subprocess is a promise that is either resolved with a successful result
object or rejected with a subprocessError
.
Returns: AsyncIterable<string>
Throws: SubprocessError
Iterates over each stdout
line, as soon as it is available.
The iteration waits for the subprocess to end (even when using break
or return
). It throws if the subprocess fails. This means you do not need to call await subprocess
.
Returns: AsyncIterable<string>
Throws: SubprocessError
Same as subprocess.stdout
but for stderr
instead.
Returns: AsyncIterable<string>
Throws: SubprocessError
Same as subprocess.stdout
but for both stdout
and stderr
.
file
: string
arguments
: string[]
options
: Options
Returns: Subprocess
Similar to the |
symbol in shells. Pipe the subprocess'sstdout
to a second subprocess's stdin
.
This resolves with that second subprocess's result. If either subprocess is rejected, this is rejected with that subprocess's error instead.
This follows the same syntax as spawn(file, arguments?, options?)
. It can be done multiple times in a row.
Type: ChildProcess
Underlying Node.js child process.
Among other things, this can be used to terminate the subprocess using .kill()
or exchange IPC message using .send()
.
When the subprocess succeeds, its promise is resolved with an object with the following properties.
Type: string
The output of the subprocess on standard output.
If the output ends with a newline, that newline is automatically stripped.
This is an empty string if either:
stdout
option is set to another value than 'pipe'
(its default value).subprocess.stdout
or subprocess[Symbol.asyncIterator]
.Type: string
Like result.stdout
but for the standard error instead.
Type: string
Like result.stdout
but for both the standard output and standard error, interleaved.
Type: string
The file and arguments that were run.
It is intended for logging or debugging. Since the escaping is fairly basic, it should not be executed directly.
Type: number
Duration of the subprocess, in milliseconds.
Type: Result | SubprocessError | undefined
If subprocess.pipe()
was used, the result or error of the other subprocess that was piped into this subprocess.
Type: Error
When the subprocess fails, its promise is rejected with this error.
Subprocesses fail either when their exit code is not 0
or when terminated by a signal. Other failure reasons include misspelling the command name or using the timeout
option.
Subprocess errors have the same shape as successful results, with the following additional properties.
This error class is exported, so you can use if (error instanceof SubprocessError) { ... }
.
Type: number | undefined
The numeric exit code of the subprocess that was run.
This is undefined
when the subprocess could not be started, or when it was terminated by a signal.
Type: string | undefined
The name of the signal (like SIGTERM
) that terminated the subprocess, sent by either:
If a signal terminated the subprocess, this property is defined and included in the error message. Otherwise it is undefined
.
This package fixes several cross-platform issues with node:child_process
. It brings full Windows support for:
shell
option). This includes running npm ...
or yarn ...
..cmd
, .bat
, and other shell files.PATHEXT
environment variable.nano-spawn
's main goal is to be small, yet useful. Nonetheless, depending on your use case, there are other ways to run subprocesses in Node.js.
Execa is a similar package: it provides the same features, but more. It is also built on top of node:child_process
, and is maintained by the same people.
On one hand, it has a bigger size:
On the other hand, it provides a bunch of additional features: scripts, template string syntax, synchronous execution, file input/output, binary input/output, advanced piping, verbose mode, graceful or forceful termination, IPC, shebangs on Windows, and much more. Also, it is very widely used and battle-tested.
We recommend using Execa in most cases, unless your environment requires using small packages (for example, in a library or in a serverless function). It is definitely the best option inside scripts, servers, or apps.
node:child_process
nano-spawn
is built on top of the node:child_process
core module.
If you'd prefer avoiding adding any dependency, you may use node:child_process
directly. However, you might miss the features nano-spawn
provides: proper error handling, full Windows support, local binaries, piping, lines iteration, interleaved output, and more.
import {execFile} from 'node:child_process';
import {promisify} from 'node:util';
const pExecFile = promisify(execFile);
const result = await pExecFile('npm', ['run', 'build']);
© 2010 - cnpmjs.org x YWFE | Home | YWFE