## File: README.md

<h1 align="center">
  Fast Node Manager (`fnm`)
  
  [](https://github.com/Schniz/fnm/actions)
</h1>

> 🚀 Fast and simple Node.js version manager, built in Rust



## Features

🌎 Cross-platform support (macOS, Windows, Linux)

✨ Single file, easy installation, instant startup

🚀 Built with speed in mind

📂 Works with `.node-version` and `.nvmrc` files

## Installation

### Using a script (macOS/Linux)

For `bash`, `zsh` and `fish` shells, there's an [automatic installation script](./.ci/install.sh).

First ensure that `curl` and `unzip` are already installed on your operating system. Then execute:

```sh
curl -fsSL https://fnm.vercel.app/install | bash
```

#### Upgrade

On macOS, it is as simple as `brew upgrade fnm`.

On other operating systems, upgrading `fnm` is almost the same as installing it. To prevent duplication in your shell config file, pass `--skip-shell` to the install command:

```sh
curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell
```

#### Parameters

`--install-dir`

Set a custom directory for fnm to be installed. The default is `$XDG_DATA_HOME/fnm` (if `$XDG_DATA_HOME` is not defined it falls back to `$HOME/.local/share/fnm` on linux and `$HOME/Library/Application Support/fnm` on MacOS).

> **Note:** On macOS, this option is only meaningful when using `--force-install` since Homebrew is the default installation method.

`--skip-shell`

Skip appending shell specific loader to shell config file, based on the current user shell, defined in `$SHELL`. e.g. for Bash, `$HOME/.bashrc`. `$HOME/.zshrc` for Zsh. For Fish - `$HOME/.config/fish/conf.d/fnm.fish`

`--force-install`

macOS installations using the installation script are deprecated in favor of the Homebrew formula, but this forces the script to install using it anyway.

Example:

```sh
curl -fsSL https://fnm.vercel.app/install | bash -s -- --install-dir "./.fnm" --skip-shell
```

### Manually

#### Using Homebrew (macOS/Linux)

```sh
brew install fnm
```

Then, [set up your shell for fnm](#shell-setup)

#### Using Winget (Windows)

```sh
winget install Schniz.fnm
```

#### Using Scoop (Windows)

```sh
scoop install fnm
```

Then, [set up your shell for fnm](#shell-setup)

#### Using Chocolatey (Windows)

```sh
choco install fnm
```

Then, [set up your shell for fnm](#shell-setup)

#### Using Cargo (Linux/macOS/Windows)

```sh
cargo install fnm
```

Then, [set up your shell for fnm](#shell-setup)

#### Using a release binary (Linux/macOS/Windows)

- Download the [latest release binary](https://github.com/Schniz/fnm/releases) for your system
- Make it available globally on `PATH` environment variable
- [Set up your shell for fnm](#shell-setup)

### Removing

To remove fnm (😢), just delete the `.fnm` folder in your home directory. You should also edit your shell configuration to remove any references to fnm (ie. read [Shell Setup](#shell-setup), and do the opposite).

## Completions

fnm ships its completions with the binary:

```sh
fnm completions --shell <SHELL>
```

Where `<SHELL>` can be one of the supported shells:

- `bash`
- `zsh`
- `fish`
- `powershell`

Please follow your shell instructions to install them.

### Shell Setup

Environment variables need to be setup before you can start using fnm.
This is done by evaluating the output of `fnm env`.

> [!TIP]
> Prefer passing an explicit shell (for example `fnm env --shell bash`) instead of relying on shell inference at runtime. It is a bit faster and avoids process tree detection.

> [!NOTE]
> Check out the [Configuration](./docs/configuration.md) section to enable highly
> recommended features, like automatic version switching.

Adding a `.node-version` to your project is as simple as:

```bash
$ node --version
v14.18.3
$ node --version > .node-version
```

Check out the following guides for the shell you use:

#### Bash

Add the following to your `.bashrc` profile:

```bash
eval "$(fnm env --use-on-cd --shell bash)"
```

#### Zsh

Add the following to your `.zshrc` profile:

```zsh
eval "$(fnm env --use-on-cd --shell zsh)"
```

#### Fish shell

Create `~/.config/fish/conf.d/fnm.fish` and add this line to it:

```fish
fnm env --use-on-cd --shell fish | source
```

#### PowerShell

Add the following to the end of your profile file:

```powershell
fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression
```

- For macOS/Linux, the profile is located at `~/.config/powershell/Microsoft.PowerShell_profile.ps1`
- For Windows location is either:
  - `%userprofile%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` Powershell 5
  - `%userprofile%\Documents\PowerShell\Microsoft.PowerShell_profile.ps1` Powershell 6+
- To create the profile file you can run this in PowerShell:
  ```powershell
  if (-not (Test-Path $profile)) { New-Item $profile -Force }
  ```
- To edit your profile run this in PowerShell:
  ```powershell
  Invoke-Item $profile
  ```

#### Windows Command Prompt aka Batch aka WinCMD

fnm is also supported but is not entirely covered. You can set up a startup script for [cmd.exe](https://superuser.com/a/144348) or [Windows Terminal](https://superuser.com/a/1855283) and append the following lines:

```batch
@echo off
:: for /F will launch a new instance of cmd so we create a guard to prevent an infnite loop
if not defined FNM_AUTORUN_GUARD (
    set "FNM_AUTORUN_GUARD=AutorunGuard"
    FOR /f "tokens=*" %%z IN ('fnm env --use-on-cd') DO CALL %%z
)
```

#### Usage with Cmder

Usage is very similar to the normal WinCMD install, apart for a few tweaks to allow being called from the cmder startup script. The example **assumes** that the `CMDER_ROOT` environment variable is **set** to the **root directory** of your Cmder installation.
Then you can do something like this:

- Make a .cmd file to invoke it

```batch
:: %CMDER_ROOT%\bin\fnm_init.cmd
@echo off
FOR /f "tokens=*" %%z IN ('fnm env --use-on-cd') DO CALL %%z
```

- Add it to the startup script

```batch
:: %CMDER_ROOT%\config\user_profile.cmd
call "%CMDER_ROOT%\bin\fnm_init.cmd"
```

You can replace `%CMDER_ROOT%` with any other convenient path too.

## [Configuration](./docs/configuration.md)

[See the available configuration options for an extended configuration documentation](./docs/configuration.md)

## [Usage](./docs/commands.md)

[See the available commands for an extended usage documentation](./docs/commands.md)

## Contributing

PRs welcome :tada:

### Developing:

```sh
# Install Rust
git clone https://github.com/Schniz/fnm.git
cd fnm/
cargo build
```

### Running Binary:

```sh
cargo run -- --help # Will behave like `fnm --help`
```

### Running Tests:

```sh
cargo test
```

---

## File: docs/commands.md

# `fnm`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm list-remote`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm list`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm install`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm use`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm env`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm completions`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm alias`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm unalias`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm default`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm current`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm exec`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm uninstall`

```
/* Detailed source-code truncated for AI context efficiency. */
```

# `fnm help`

```

```

---

## File: docs/configuration.md

# Configuration

fnm comes with many features out of the box. Some of them are not activated by default as they’re changing your shell default behavior, and some are just a feature flag to avoid breaking changes or just experimental until we decide it is worthwhile to introduce them.

All these features can be configured by adding flags to the `fnm env` call when initializing the shell. For instance, if your shell set up looks like `eval "$(fnm env)"` then you can add a flag to it by changing it to `eval "$(fnm env --my-flag=value)"`

Here’s a list of these features and capabilities:

### `--use-on-cd`

**✅ Highly recommended**

`--use-on-cd` appends output to `fnm env`'s output that will hook into your shell upon changing directories, and will switch the Node.js version based on the requirements of the current directory, based on `.node-version` or `.nvmrc` (or `packages.json#engines#node` if `--resolve-engines` was enabled).

This allows you do avoid thinking about `fnm use`, and only `cd <DIR>` to make it work.

### `--version-file-strategy=recursive`

**✅ Highly recommended**

Makes `fnm use` and `fnm install` take parent directories into account when looking for a version file ("dotfile")--when no argument was given.

So, let's say we have the following directory structure:

```
repo/
├── package.json
├── .node-version <- with content: `20.0.0`
└── packages/
  └── my-package/ <- I am here
    └── package.json
```

And I'm running the following command:

```sh-session
repo/packages/my-package$ fnm use
```

Then fnm will switch to Node.js v20.0.0.

Without the explicit flag, the value is set to `local`, which will not traverse the directory tree and therefore will print:

```sh-session
repo/packages/my-package$ fnm use
error: Can't find version in dotfiles. Please provide a version manually to the command.
```

### `--corepack-enabled`

**🧪 Experimental**

Runs [`corepack enable`](https://nodejs.org/api/corepack.html#enabling-the-feature) when a new version of Node.js is installed. Experimental due to the fact Corepack itself is experimental.

### `--resolve-engines`

**🧪 Experimental**

Treats `package.json#engines#node` as a valid Node.js version file ("dotfile"). So, if you have a package.json with the following content:

```json
{
  "engines": {
    "node": ">=20 <21"
  }
}
```

Then:

- `fnm install` will install the latest satisfying Node.js 20.x version available in the Node.js dist server
- `fnm use` will use the latest satisfying Node.js 20.x version available on your system, or prompt to install if no version matched.

---

## File: docs/nightly.md

# Working with Node nightly builds

fnm doesn't give you any shorthands to install nightly builds, but you can
do that by manually passing a "dist mirror" with the `--node-dist-mirror` flag. 

## Example usage

Here's an example of installing Node 23.

To get a list of available versions run this:

    fnm --node-dist-mirror https://nodejs.org/download/nightly/ ls-remote

To use and install nightly version run this:

    fnm --node-dist-mirror https://nodejs.org/download/nightly/ use 23
    # or
    fnm --node-dist-mirror https://nodejs.org/download/nightly/ use v23.0.0-nightly202407253de7a4c374

Once you installed it you would be able to see that version in you list:

    fnm ls

And use it without providing `--node-dist-mirror` flag:

    fnm use 23