# nvm_find_up: How NVM Traverses Directories to Find .nvmrc Files

> Learn how nvm_find_up traverses directories upwards from your current location to find .nvmrc files. Understand nvm's search logic for .nvmrc.

- Repository: [nvm.sh/nvm](https://github.com/nvm-sh/nvm)
- Tags: internals
- Published: 2026-02-27

---

**The `nvm_find_up` function is a POSIX-compliant directory traversal utility in nvm that walks upward from the current working directory until it locates a specified file, primarily used to discover `.nvmrc` files in parent directories.**

The `nvm_find_up` function serves as the foundational mechanism enabling Node Version Manager (nvm) to automatically detect project-specific Node.js versions. Defined in the core [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh) script of the [nvm-sh/nvm](https://github.com/nvm-sh/nvm) repository, this helper function implements a robust upward directory search algorithm that underpins nvm's automatic version switching capabilities.

## What is nvm_find_up?

`nvm_find_up` is a shell function designed to locate files by traversing the directory hierarchy from the current working directory toward the filesystem root. Unlike external dependencies, this function is self-contained within nvm's codebase, ensuring portability across POSIX-compliant shells.

The function accepts a single argument: the filename to search for. When invoked, it returns the directory path containing the target file, or the final traversed path if the file is not found. This return value is printed via `nvm_echo`, making it capturable in shell variables or command substitution.

## How nvm_find_up Traverses Directories

The directory traversal mechanism employed by `nvm_find_up` relies on pure shell parameter expansion, eliminating the need for external utilities like `find` or `dirname`. This approach ensures maximum compatibility across different operating systems and shell environments.

### The Directory Climbing Algorithm

The algorithm executes through the following precise steps:

1. **Initialization**: Sets `path_` to the current working directory (`$PWD`).

2. **Conditional Loop**: Continues iterating while three conditions remain true:
   - The path is not empty
   - The path is not `.` (current directory symbol)
   - The target file does not exist at `${path_}/${1-}` (where `$1` is the function argument)

3. **Path Truncation**: Strips the last directory component using shell parameter expansion:
   ```sh
   path_=${path_%/*}
   ```

   This `${var%/*}` syntax removes the shortest match of `/*` from the end of the variable, effectively performing a `dirname` operation.

4. **Termination**: Exits when the file is found or the root/empty path is reached, then outputs the result via `nvm_echo`.

### Source Code Location

The implementation resides in **[`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh)** at **lines 500-507**:

```sh

# Traverse up in directory tree to find containing folder

nvm_find_up() {
  local path_
  path_="${PWD}"
  while [ "${path_}" != "" ] && [ "${path_}" != '.' ] && [ ! -f "${path_}/${1-}" ]; do
    path_=${path_%/*}
  done
  nvm_echo "${path_}"
}

```

This compact implementation demonstrates efficient use of shell builtins to achieve filesystem traversal without subprocess overhead.

## Practical Examples of nvm_find_up

Understanding the theoretical operation of `nvm_find_up` becomes clearer through practical application scenarios. These examples demonstrate how nvm utilizes this function and how developers can leverage similar patterns.

### Locating .nvmrc from Subdirectories

Consider a project structure where `.nvmrc` resides in the repository root, but you are working in a deeply nested subdirectory:

```sh

# Current location: /home/user/project/src/components/button

# Target file location: /home/user/project/.nvmrc

# Capture the directory containing .nvmrc

nvm_dir=$(nvm_find_up '.nvmrc')

echo "$nvm_dir"

# Output: /home/user/project

```

This capability enables nvm to automatically detect project-specific Node.js versions regardless of your current working directory within the project tree.

### Using nvm_find_up in Custom Scripts

Developers can utilize `nvm_find_up` for locating configuration files beyond `.nvmrc`. The function works with any filename:

```sh

# Find the nearest package.json up the tree

project_root=$(nvm_find_up 'package.json')

if [ -n "$project_root" ]; then
  echo "Found package.json in: $project_root"
else
  echo "No package.json found in parent directories"
fi

```

This pattern proves useful for build scripts that need to locate project boundaries or configuration files.

### Building Higher-Order Functions

Nvm itself builds upon `nvm_find_up` with wrapper functions like `nvm_find_nvmrc`, which adds specific logic for `.nvmrc` validation:

```sh
nvm_find_nvmrc() {
  local dir
  dir="$(nvm_find_up '.nvmrc')"
  [ -e "${dir}/.nvmrc" ] && nvm_echo "${dir}/.nvmrc"
}

```

This wrapper demonstrates how `nvm_find_up` serves as a primitive operation for more complex file discovery logic within the nvm ecosystem.

## Summary

- **`nvm_find_up`** is a POSIX-compliant shell function in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh) (lines 500-507) that traverses directories upward from `$PWD` to locate specified files.

- The function uses **shell parameter expansion** (`${path_%/*}`) rather than external utilities, stripping the last path component iteratively until the target file is found or the root is reached.

- **Primary use case** involves locating `.nvmrc` files to enable automatic Node.js version switching, though the function works with any filename.

- The algorithm checks three conditions in its loop: path not empty, path not `.`, and file not existing at the current path level.

## Frequently Asked Questions

### How does nvm_find_up differ from using the find command?

**`nvm_find_up` uses pure shell builtins rather than external processes.** While `find` requires spawning a subprocess and traversing downward from a specified root, `nvm_find_up` operates within the current shell environment using parameter expansion to climb the directory tree. This approach ensures compatibility across systems where `find` might have different implementations or be unavailable, and it avoids the performance overhead of process creation.

### What happens if nvm_find_up reaches the filesystem root without finding the file?

**The function returns the final path reached during traversal.** When `nvm_find_up` climbs to the root directory (or an empty path) without locating the target file, it exits the while loop and outputs the current value of `path_` via `nvm_echo`. For wrapper functions like `nvm_find_nvmrc`, this output is then validated with an existence check (`[ -e "${dir}/.nvmrc" ]`) to determine whether to return the full file path or nothing at all.

### Can nvm_find_up be used outside of nvm for general file searching?

**Yes, the function can be adapted for general use within shell scripts.** While `nvm_find_up` is defined within [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh), its implementation relies only on POSIX shell features (local variables, parameter expansion, and test commands). Developers can extract this function into standalone utility scripts to locate configuration files, project markers (like [`package.json`](https://github.com/nvm-sh/nvm/blob/main/package.json) or `.git`), or any upward-traversal file search needs. However, since it depends on `nvm_echo` for output, users would need to either source nvm or replace that call with `printf '%s\n'` for standalone operation.