CLI Options

A reference for nstd commands, runtime options, and NODE_OPTIONS.

This page lists everything the nstd command accepts: the commands, the options you can put in front of a script, and what NODE_OPTIONS can hold.

#Commands

nstd script.js [args...]       # run a file
nstd run script.js [args...]   # the same, spelled out
nstd -e 'code'                 # evaluate a string
nstd -p 'code'                 # evaluate a string and print the result
nstd --print-realm             # list the builtin modules this build provides
nstd -v                        # print the version
nstd -h                        # print usage
CommandWhat it does
<file> [args...]Run <file> as the program.
run <file> [args...]The same, spelled out.
-e, --eval <code>Run <code> as CommonJS.
-p, --print <code>Run <code> and print its result.
--print-realmStart up and report which builtin modules are available.
-v, --versionPrint the version and exit.
-h, --helpPrint usage and exit.

#Options

Options go before the file (or before -e, -p or --print-realm). Inside your program they appear in process.execArgv, exactly as typed, the same as under node.

OptionWhat it does
-r, --require <file>Load a CommonJS module before the program starts. Repeatable.
-C, --conditions <name>Add a custom condition for "exports"/"imports". Repeatable.
--preserve-symlinksResolve dependencies to the symlink path instead of its target.
--preserve-symlinks-mainThe same, for the entry file.
--unhandled-rejections <mode>Choose what happens to unhandled rejections.
--stack-trace-limit=<n>How many stack frames an Error keeps (default 10).
--dns-result-order <order>The default address order for dns.lookup().
--title <name>Set process.title (and, on Linux, the name ps shows).
--no-warningsHide all process warnings.
--disable-warning <code|name>Hide one warning by its code or name. Repeatable.
--trace-warningsPrint a stack trace with every warning.
--trace-deprecationPrint a stack trace with deprecation warnings only.
--throw-deprecationTurn deprecation warnings into thrown errors.
--pending-deprecationShow deprecation warnings that are off by default.
--no-deprecationHide all deprecation warnings.
--redirect-warnings <file>Append warnings to <file> instead of stderr.
--experimental-eventsourceAdd globalThis.EventSource.
--no-experimental-websocketRemove globalThis.WebSocket and globalThis.CloseEvent.
--experimental-stream-iterEnable node:stream/iter and node:zlib/iter.
--experimental-benchEnable node:bench and node:bench/reporters.
--experimental-require-moduleAllow require() of ES modules. On by default.
--no-experimental-require-moduleDisallow require() of ES modules.
--experimental-vfsAllow require("node:vfs"). On by default.
--expose-gcAdd globalThis.gc() to trigger garbage collection.
--expose-internalsAllow require() of Node's internal/* modules.

The sections below explain the options that need more than one line.

#Running code

#-p, --print

-p works like -e, but also prints what the code evaluates to. It behaves exactly like node -p:

nstd -p '1 + 1'                # 2
nstd -p '"hi"'                 # hi   (strings print without quotes)
nstd -p 'new Map([["a", 1]])'  # Map(1) { 'a' => 1 }
nstd -p 'let x = 5'            # undefined   (a declaration has no value)

The result is printed the way console.log would print it. It's printed once the program has otherwise finished, so anything the code started, such as a timer, still runs first:

nstd -p 'setTimeout(() => console.log("timer"), 1) && "done"'
# timer
# done

If the code throws, nothing is printed.

One difference from node: -p always needs code after it. node -p on its own reads the program from stdin, but nstd -p reports -p requires an argument and exits with 9. To run code from stdin, pipe it into plain nstd (it runs, but the result isn't printed).

#-r, --require

Loads a CommonJS module before your program starts. Repeat it, in either spelling, to load several in order:

nstd -r ./a.cjs --require=./b.cjs script.js

Command-line options aren't passed on to child processes started with child_process.fork() or by running process.execPath. To preload a module in those too, put it in NODE_OPTIONS. See also Running Code.

#Module resolution

#-C, --conditions

Adds a custom condition used when resolving a package's "exports" and "imports", for both require() and import(). Repeat it, in either spelling, to add several:

nstd -C custom --conditions=other script.js

A package whose "exports" has a custom entry now resolves to it instead of default.

Note that -C=custom does not work. Like node, short options don't accept =, so this is reported as bad option and exits with 9.

#Errors and stack traces

#--unhandled-rejections

Chooses what happens when a promise is rejected and nothing handles it:

ModeWhat happens
throw (default)Treated as an uncaught exception, unless an unhandledRejection listener handles it.
strictAlways treated as an uncaught exception.
warnPrint a warning and keep running.
warn-with-error-codePrint a warning, keep running, and exit with 1 at the end.
noneIgnore it.
nstd --unhandled-rejections=none script.js

Any other value is rejected before the program starts, with invalid value for --unhandled-rejections and exit code 9.

#--stack-trace-limit

Sets how many stack frames an Error keeps. The default is 10, and 0 keeps none.

nstd --stack-trace-limit=25 script.js

You must use the = form. --stack-trace-limit 25 (with a space) is rejected with exit code 9, just as node rejects it.

#Warnings

Every warning nstd raises is emitted as a "warning" event on process, with an Error that has a name, a message and usually a code. Your program can listen for them:

process.on("warning", (warning) => {
  console.error(warning.name, warning.code, warning.message);
});

nstd prints warnings using Node's own built-in listener, so the output and the options below behave the same as in node:

  • --no-warnings (or NODE_NO_WARNINGS=1) hides every warning.

  • --disable-warning hides a single warning by its code or name, and can be repeated:

    nstd --disable-warning=DEP0040 --disable-warning=ExperimentalWarning app.js

    It also works for nstd's own UnsupportedOptionWarning.

  • --trace-warnings prints a stack trace with each warning. --trace-deprecation does the same, but only for deprecation warnings.

  • --throw-deprecation turns a deprecation warning into an error. As in node, the error is thrown one tick later, so the deprecated call still returns and the program then stops with an uncaught exception.

  • --pending-deprecation shows deprecation warnings that are normally hidden.

  • --no-deprecation hides every deprecation warning, including pending ones, and sets process.noDeprecation to true.

  • --redirect-warnings <file> appends warnings to a file instead of printing them to stderr. If the file can't be opened, warnings go to stderr instead. Unlike node, --diagnostic-dir does not redirect warnings here (it's ignored), so this is the only way to move them.

#Process

#--title

Sets the name of the process:

nstd --title=my-worker script.js

process.title reads it back on every platform, and you can change it at any time:

console.log(process.title); // my-worker
process.title = "phase-two";

On Linux, nstd also renames the process at the operating-system level, so tools like ps and top show the new name:

$ nstd --title=my-worker script.js &
$ ps -o comm=,args= -p $!
my-worker       my-worker

Note

On every other platform, including WASI and macOS, only process.title changes. ps keeps showing the original command, and nstd doesn't warn about it. If you rely on --title so that ps or a process supervisor shows a name, that only works on Linux.

A few small differences from node:

  • Without --title, process.title is "nstd". In node it's the path the binary was started with.
  • A very long title reads back in full. node cuts it short to fit the space the operating system gives it; nstd only shortens the copy that ps sees.
  • On Linux, ps -o comm shows my-worker for the example above, where node shows node-MainThread, because node renames its main thread after applying the title.

--title= with nothing after it is an error (exit code 9), and --title "" is accepted and leaves the title unchanged, both matching node.

#--dns-result-order

Sets the order in which dns.lookup() returns addresses, and what dns.getDefaultResultOrder() reports:

  • verbatim (default) keeps the order the resolver returned.
  • ipv4first puts IPv4 addresses first.
  • ipv6first puts IPv6 addresses first.

As in node, an invalid value isn't caught when the command line is read. The program starts, then fails with ERR_INVALID_ARG_VALUE and exit code 1.

#Globals

#--experimental-eventsource and --no-experimental-websocket

These control whether EventSource, WebSocket and CloseEvent exist as globals:

  • EventSource is missing by default, as in node. Pass --experimental-eventsource to add it.
  • WebSocket and CloseEvent exist by default. Pass --no-experimental-websocket to remove them.

#--expose-gc

Adds globalThis.gc(), which runs a real garbage collection. That's enough to reliably clear a WeakRef or trigger a FinalizationRegistry callback. Calling gc({ type: "major-snapshot" }) is not supported, because there's no heap profiler to write a snapshot.

#--expose-internals

Lets require() load Node's own internal/* modules. This is meant for testing and debugging, just like node --expose-internals. Ordinary programs never need it.

#NODE_OPTIONS

nstd reads options from the NODE_OPTIONS environment variable before the command line, and accepts the same options listed above:

NODE_OPTIONS='--require ./setup.cjs --no-warnings' nstd script.js

It works the same way as in node:

  • Spaces separate options. Double quotes group text that contains spaces, and \ escapes a character inside quotes.
  • Options from NODE_OPTIONS take effect but don't appear in process.execArgv, which only lists what was typed on the command line.
  • Options that choose what to run, such as --eval and --prof, aren't allowed in NODE_OPTIONS and are rejected like an unknown option.
  • Options nstd ignores (see below) produce the same warning here as on the command line.

#Unsupported options

nstd handles Node options it doesn't implement in one of two ways, depending on whether ignoring them could change what your program does.

#Ignored options

Many scripts and CI setups pass options that only affect diagnostics or performance, such as --cpu-prof, --max-old-space-size=4096, --inspect or the --report-* family. nstd has no V8 heap, profiler or inspector, so it can't honor them. Instead of failing, it runs your program anyway and prints a single warning:

$ nstd --cpu-prof --max-old-space-size=64 script.js
(nstd) UnsupportedOptionWarning: --cpu-prof, --max-old-space-size are accepted
and ignored: nstd does not implement them, and the program runs as if they had
not been passed.

You get one warning per run no matter how many such options you pass, and --no-warnings or --disable-warning=UnsupportedOptionWarning hides it. The options still appear in process.execArgv, as in node, but have no effect. nstd --help lists every option in this group.

An option is only ignored if skipping it costs you information or speed, never correctness or security. A missing profile or a missing memory limit doesn't change what your program computes.

#Rejected options

Every other option is treated like a typo: nstd prints bad option: <name> and exits with code 9, just as node does for an option it doesn't know. Nothing is silently accepted and dropped.

Some examples, and why they're rejected rather than ignored:

  • --permission and --allow-* ask for a sandbox nstd doesn't have. Ignoring them would give your program more access than you asked for.
  • -c, --check would run a program you only wanted to syntax-check.
  • --test would run your program instead of its tests, and report success.
  • --watch would exit where you expected the process to keep running.

This can seem strict, but it saves you time. An option that silently does nothing lets your program start normally and then fail later, somewhere that seems unrelated. Rejecting it up front points straight at the real cause.