
# 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

```sh
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
```

| Command                | What 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-realm`        | Start up and report which builtin modules are available. |
| `-v`, `--version`      | Print the version and exit.                              |
| `-h`, `--help`         | Print 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`.

| Option                             | What 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-symlinks`              | Resolve dependencies to the symlink path instead of its target. |
| `--preserve-symlinks-main`         | The 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-warnings`                    | Hide all process warnings.                                      |
| `--disable-warning <code\|name>`   | Hide one warning by its code or name. Repeatable.               |
| `--trace-warnings`                 | Print a stack trace with every warning.                         |
| `--trace-deprecation`              | Print a stack trace with deprecation warnings only.             |
| `--throw-deprecation`              | Turn deprecation warnings into thrown errors.                   |
| `--pending-deprecation`            | Show deprecation warnings that are off by default.              |
| `--no-deprecation`                 | Hide all deprecation warnings.                                  |
| `--redirect-warnings <file>`       | Append warnings to `<file>` instead of stderr.                  |
| `--experimental-eventsource`       | Add `globalThis.EventSource`.                                   |
| `--no-experimental-websocket`      | Remove `globalThis.WebSocket` and `globalThis.CloseEvent`.      |
| `--experimental-stream-iter`       | Enable `node:stream/iter` and `node:zlib/iter`.                 |
| `--experimental-bench`             | Enable `node:bench` and `node:bench/reporters`.                 |
| `--experimental-require-module`    | Allow `require()` of ES modules. On by default.                 |
| `--no-experimental-require-module` | Disallow `require()` of ES modules.                             |
| `--experimental-vfs`               | Allow `require("node:vfs")`. On by default.                     |
| `--expose-gc`                      | Add `globalThis.gc()` to trigger garbage collection.            |
| `--expose-internals`               | Allow `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`:

```sh
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:

```sh
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:

```sh
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`](#node_options). See also
[Running Code](/runtime/running-code#load-a-module-first).

## 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:

```sh
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:

| Mode                   | What happens                                                                          |
| ---------------------- | ------------------------------------------------------------------------------------- |
| `throw` (default)      | Treated as an uncaught exception, unless an `unhandledRejection` listener handles it. |
| `strict`               | Always treated as an uncaught exception.                                              |
| `warn`                 | Print a warning and keep running.                                                     |
| `warn-with-error-code` | Print a warning, keep running, and exit with `1` at the end.                          |
| `none`                 | Ignore it.                                                                            |

```sh
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.

```sh
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:

```js
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:

  ```sh
  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](#ignored-options)), so this is the only way to move them.

## Process

### `--title`

Sets the name of the process:

```sh
nstd --title=my-worker script.js
```

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

```js
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:

```console
$ 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:

```sh
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:

```sh
$ 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.
