# How nvm Handles io.js (Deprecated) Installations and Migrations

> Learn how nvm manages deprecated io.js installations and migrations using prefix-aware functions in nvm.sh. Effortlessly switch between Node.js and io.js versions.

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

---

**nvm treats io.js as a separate runtime flavor using prefix-aware helper functions in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh) to manage versioning, downloads, and migrations without duplicating core logic.**

The `nvm` (Node Version Manager) project maintains legacy support for the discontinued **io.js** runtime through a flavor abstraction system implemented in its core shell script. Even though the io.js project merged back into Node.js in 2015 with the release of Node 4.0.0, `nvm` continues to handle **io.js installations and migrations** using dedicated prefix helpers that intercept version strings before they reach the standard Node management pipeline. This architecture allows users to install historical io.js releases, switch between io.js and Node versions, and migrate projects to modern Node runtimes seamlessly.

## Prefix Helpers – The Foundation of io.js Detection

All io.js specific logic in `nvm` relies on four essential helper functions defined in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh) that normalize version strings by adding or removing the `iojs-` prefix.

- **`nvm_iojs_prefix`** (line 1419): Returns the literal string `iojs` used to identify the flavor throughout the script.
- **`nvm_is_iojs_version`** (line 1426): Tests whether a version string begins with `iojs-` to determine which code path to execute.
- **`nvm_add_iojs_prefix`** (line 1431): Adds the `iojs-` prefix to a plain semantic version (e.g., transforms `1.0.0` into `iojs-1.0.0`).
- **`nvm_strip_iojs_prefix`** (line 1435): Removes the `iojs-` prefix to return a canonical version number for internal comparison.

These functions enable higher-level commands like `nvm_resolve_alias` and `nvm_version` to handle io.js versions transparently. When `nvm` encounters a version string, it first calls `nvm_is_iojs_version` to detect the flavor, uses `nvm_strip_iojs_prefix` to work with the raw semver internally, and applies `nvm_add_iojs_prefix` when displaying results to the user.

## Listing Installed and Remote io.js Versions

### Local Listing with `nvm ls`

When you run `nvm ls` with an io.js pattern, the script detects the flavor and routes the request appropriately.

1. **Flavor Detection**: The code checks `nvm_is_iojs_version` (lines 1550‑1556) to determine if the search pattern refers to io.js.
2. **Directory Resolution**: It selects the `$NVM_DIR/versions/iojs` directory via `nvm_version_dir iojs` rather than the standard Node versions directory.
3. **Prefix Management**: After stripping the prefix for internal matching against installed directories, `nvm` re-adds it for display output.

### Remote Listing with `nvm ls-remote iojs`

To fetch available io.js releases from the legacy mirror:

- The entry point **`nvm_ls_remote_iojs`** (line 1635) acts as a thin wrapper.
- It delegates to **`nvm_ls_remote_index_tab`** with the flavor argument set to `iojs`, which injects the `iojs-` prefix before each version number (lines 1663‑1665).
- The index file downloads from **`https://iojs.org/dist/index.tab`**, as resolved by `nvm_get_mirror` (line 2226).

This allows `nvm ls-remote iojs` to display historical releases like `iojs-3.3.1` and `iojs-3.2.0` even though the project is no longer actively maintained.

## Downloading and Installing io.js Artifacts

The installation pipeline for io.js reuses the same core logic as Node, with only the mirror URL and directory structure differing.

When you execute `nvm install iojs-3.3.1`, the following occurs:

1. **Normalization**: `nvm_strip_iojs_prefix` removes the prefix to obtain the canonical version `v3.3.1`.
2. **Slug Generation**: `nvm_get_download_slug` (lines 3767‑3769) constructs the filename for binary or source archives using the `iojs` flavor identifier.
3. **Mirror Selection**: `nvm_get_mirror` returns `https://iojs.org/dist` (line 2226) instead of the Node.js distribution URL.
4. **Extraction**: `nvm_download` fetches the tarball, and either `nvm_install_binary` or `nvm_install_source` extracts it into `$NVM_DIR/versions/iojs/iojs-3.3.1`.

## Switching Between io.js and Node Versions

The `nvm use <version>` command resolves the installation path and updates your shell's `PATH` environment variable. When switching to an io.js version:

- The resolved path uses `nvm_add_iojs_prefix` to ensure the directory name includes the prefix (e.g., `iojs-3.3.1`).
- `nvm` prepends `$NVM_DIR/versions/iojs/iojs-3.3.1/bin` to your `PATH`.
- Upon successful activation, the script outputs: `Now using io.js 3.3.1 (npm v2.14.12)` (referenced at line 3978).

## Uninstalling io.js Versions

Removing an io.js installation follows the standard uninstallation flow, with flavor-specific messaging. When you run `nvm uninstall iojs-3.3.1`, the script removes the directory and prints an explicit confirmation: `Uninstalled io.js 3.3.1` (line 3776).

## Migrating from io.js to Modern Node

Because `nvm` normalizes versions internally, migrating from the deprecated io.js line to modern Node requires only standard `nvm` commands. The `--reinstall-packages-from` flag (documented at line 3127) facilitates global package migration between flavors.

```bash

# Install the latest stable Node

nvm install node

# Copy global npm packages from iojs-3.3.1 to the current Node version

nvm reinstall-packages iojs-3.3.1

# Remove the deprecated io.js version

nvm uninstall iojs-3.3.1

```

Even though io.js ended at version 3.3.1, these code paths remain functional in `nvm`, ensuring legacy projects can continue running or transition cleanly to the unified Node.js runtime.

## Summary

- **Flavor Abstraction**: `nvm` uses prefix helpers (`nvm_is_iojs_version`, `nvm_strip_iojs_prefix`, `nvm_add_iojs_prefix`) to treat io.js as a distinct runtime flavor within [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh).
- **Legacy Mirror Support**: Downloads resolve to `https://iojs.org/dist` via `nvm_get_mirror`, while installations store files in `$NVM_DIR/versions/iojs/`.
- **Unified Commands**: Standard `nvm install`, `nvm use`, `nvm ls`, and `nvm uninstall` commands work with `iojs-` prefixed versions without requiring separate subcommands.
- **Migration Tools**: The `nvm reinstall-packages` command transfers global packages between io.js and Node installations, simplifying upgrades from the deprecated runtime.

## Frequently Asked Questions

### Can I still install io.js with nvm today?

Yes. `nvm` continues to support installing historical io.js versions from the legacy mirror at `iojs.org`. You can run `nvm install iojs-3.3.1` or any previous release, and the binaries will download and install into `$NVM_DIR/versions/iojs/` just as they did when the project was active.

### How do I migrate global npm packages from io.js to Node?

Use the `nvm reinstall-packages` command. First install your target Node version with `nvm install node`, then run `nvm reinstall-packages iojs-<version>` where `<version>` is your old io.js release. This copies globally installed packages from the io.js environment to the currently active Node version.

### Where does nvm store io.js versions on disk?

io.js versions reside in a separate directory hierarchy at `$NVM_DIR/versions/iojs/` rather than `$NVM_DIR/versions/node/`. Each version is stored in a subdirectory named with the `iojs-` prefix (e.g., `iojs-3.3.1`), ensuring no filename collisions with Node.js releases of the same version number.

### Will nvm remove support for io.js in future releases?

There are no plans to remove io.js support. The implementation in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh) is non-intrusive, relying on the same core functions used for Node management. Maintaining backward compatibility for the deprecated runtime requires minimal overhead while preserving functionality for legacy codebases that still depend on io.js-specific behavior.