NVM vs NPM vs Node.js: What's the Difference? Complete Guide

2024/01/01 2026/05/16
NVM vs NPM vs Node.js: What's the Difference? Complete Guide

When starting out with JavaScript development, you will inevitably encounter three terms: NVM, NPM, and Node.js. In short, Node.js is the JavaScript runtime, NPM is the package manager that ships with Node.js, and NVM is a version manager that lets you install and switch between multiple Node.js versions on the same machine. This article breaks down NVM vs NPM vs Node.js in detail, including the correct installation flow, essential commands, and best practices for team collaboration.

NVM vs NPM vs Node.js — Quick Overview

Before diving into each tool individually, here is a side-by-side comparison table that clarifies the role of NVM, NPM, and Node.js:

AspectNode.jsNPMNVM
What it isJavaScript runtime environmentPackage managerNode.js version manager
Primary purposeExecute JavaScript on the serverInstall, manage, and publish packagesInstall and switch between Node.js versions
InstallationDownload from nodejs.org or install via NVMAuto-installed with Node.jsInstall via curl script or Homebrew
Key commandsnode, node -vnpm install, npm runnvm install, nvm use
Config filesNone (uses env variables)package.json, .npmrc.nvmrc
Install location/usr/local/bin/node or ~/.nvm/versions/Ships with Node.js; global packages in npm root~/.nvm/

A simple analogy:

  • Node.js is the engine (lets JavaScript run outside the browser)
  • NPM is the fuel station (provides packages/libraries)
  • NVM is the garage (stores and manages multiple engine versions)

What Is Node.js?

Node.js is an open-source, cross-platform runtime environment built on Google Chrome’s V8 JavaScript engine. It enables JavaScript to run outside the browser — on servers, desktops, and IoT devices.

The V8 Engine

V8 is Google’s high-performance JavaScript engine, originally built to speed up JavaScript execution in Chrome. Its core innovation is JIT (Just-In-Time) compilation, which compiles JavaScript directly to machine code at runtime rather than interpreting it line by line. Node.js extracts V8 from the browser, allowing JavaScript code to execute natively on any operating system.

Why Use Node.js for Backend Development?

Before Node.js, backend development required languages like PHP, Java, Python, or Ruby. Frontend engineers who wanted to build server-side logic had to learn an entirely different language. Node.js lets developers use a single language — JavaScript — for both client and server code, dramatically lowering the barrier to full-stack development.

Node.js also introduces non-blocking I/O and an event-driven architecture. Traditional multi-threaded servers block a thread while waiting for database queries or file reads. Node.js uses a single-threaded event loop that continues processing other requests during I/O waits, making it ideal for high-concurrency applications like real-time chat, streaming services, and API gateways.

LTS vs Current Release Strategy

Node.js maintains two release channels:

ChannelDescriptionRecommended for
LTS (Long Term Support)Stable, with extended bug-fix support (18 months Active + 12 months Maintenance)Production, enterprise projects
CurrentLatest features, new major version every 6 months, less battle-testedDevelopment, experimenting with new APIs

Even-numbered major versions (18, 20, 22) become LTS releases. Odd-numbered versions (19, 21) receive short-term maintenance only. Always use LTS for production workloads.

Common Node.js Use Cases

  • API servers — Build RESTful or GraphQL APIs with Express.js, Fastify, or Hono.
  • CLI tools — Tools like ESLint, Webpack, and Vite are all built on Node.js.
  • SSR (Server-Side Rendering) — Frameworks like Next.js and Nuxt render pages on the server for better SEO.
  • Real-time applications — WebSocket-based chat, notifications, and collaborative editing.
  • Microservices — Node.js’s lightweight footprint is ideal for containerized microservice architectures.
# Check current Node.js version
node -v

# Start the REPL (interactive mode)
node

# Run a JavaScript file
node index.js

# List Node.js built-in modules
node -e "console.log(require('module').builtinModules)"

What Is NPM (Node Package Manager)?

NPM (Node Package Manager) is the default package manager for Node.js and is installed automatically alongside it. NPM provides a command-line interface for installing, updating, and managing third-party packages, as well as a public registry — the world’s largest open-source software repository with over 2 million packages as of 2024.

Essential npm Commands

CommandDescription
npm initInitialize a new project and create package.json
npm init -yInitialize with default values (skip prompts)
npm installInstall all dependencies from package.json
npm install <pkg>Install a package and add to dependencies
npm install <pkg> --save-devInstall and add to devDependencies
npm install -g <pkg>Install a package globally
npm uninstall <pkg>Remove a package
npm updateUpdate all packages to the latest allowed version
npm run <script>Run a script defined in package.json
npm listList installed packages
npm outdatedShow packages with newer versions available

package.json and package-lock.json

package.json is the project manifest. It records the project name, version, scripts, and dependency version ranges.

package-lock.json is an auto-generated lock file that pins the exact resolved version of every package (including transitive dependencies). It guarantees that different machines and CI/CD environments reproduce the identical dependency tree.

{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "build": "webpack --mode production",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "nodemon": "^3.0.1",
    "jest": "^29.7.0"
  }
}

dependencies vs devDependencies

  • dependencies — Packages required at runtime in production (e.g., express, react, axios).
  • devDependencies — Packages needed only during development (e.g., jest, webpack, prettier). These are excluded when deploying with npm install --production.

Semantic Versioning (SemVer)

NPM follows the SemVer specification: MAJOR.MINOR.PATCH.

  • MAJOR — Incompatible API changes (breaking)
  • MINOR — New backward-compatible features
  • PATCH — Backward-compatible bug fixes

Version range symbols in package.json:

SymbolExampleMeaning
^ (caret)^4.18.2Allows updates within 4.x.x (does not cross major)
~ (tilde)~4.18.2Allows updates within 4.18.x (does not cross minor)
* (wildcard)*Any version (not recommended for production)
None4.18.2Exact pinned version

What Is NVM (Node Version Manager)?

NVM (Node Version Manager) is a tool that lets you install and manage multiple Node.js versions on a single machine and switch between them with a single command.

Why Manage Multiple Node.js Versions?

In real-world development, you often maintain several projects simultaneously:

  • Project A requires Node.js 16 (a legacy dependency does not support newer versions)
  • Project B uses Node.js 20 LTS
  • Project C needs Node.js 22 to test new runtime features

Without a version manager, switching Node.js versions means uninstalling and reinstalling — a tedious and error-prone process. NVM makes version switching instant.

How NVM Works

NVM installs each Node.js version under the user’s home directory (~/.nvm/versions/). Each version has its own node and npm binaries, completely isolated from one another. When you run nvm use <version>, NVM updates your shell’s PATH to point to the selected version’s binaries.

Because NVM operates in user space, you never need sudo for installations — eliminating an entire class of permission issues.

NVM Essential Commands

# Check NVM version
nvm --version

# List all available remote versions
nvm ls-remote

# List only LTS versions
nvm ls-remote --lts

# Install the latest LTS version
nvm install --lts

# Install a specific version
nvm install 20.10.0

# List locally installed versions
nvm ls

# Switch to a specific version
nvm use 20

# Switch to the latest LTS
nvm use --lts

# Set default version (used by new shell sessions)
nvm alias default 20

# Show the currently active version
nvm current

# Uninstall a specific version
nvm uninstall 16

Installation Flow: The Right Order

The recommended installation sequence is: NVM first → Use NVM to install Node.js → NPM comes bundled automatically.

Avoid downloading Node.js directly from the official website. That approach makes version switching difficult and can cause global permission conflicts.

Step 1: Install NVM

macOS / Linux:

# Install NVM using the official script (check GitHub for latest version)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# Reload your shell configuration
source ~/.bashrc   # For Bash
source ~/.zshrc    # For Zsh (macOS default)

# Verify installation
nvm --version

The install script automatically adds NVM initialization code to your .bashrc or .zshrc.

Windows:

Windows users should use nvm-windows, a separate project with similar commands but a native Windows implementation.

Step 2: Install Node.js via NVM

# Install the latest LTS version (recommended)
nvm install --lts

# Install a specific major version
nvm install 20

# Set it as the default
nvm alias default 20

# Verify
node -v
npm -v

Step 3: NPM Is Automatically Installed

Once Node.js is installed, NPM is ready to use — no extra steps required:

# Check npm version
npm -v

# Optionally update npm to the latest
npm install -g npm@latest

npm install vs npm ci

Both commands install dependencies, but they serve different purposes:

Aspectnpm installnpm ci
Source of truthpackage.json + lock fileLock file only
Lock file mismatchUpdates lock fileThrows error and exits
node_modulesIncremental update (preserves existing)Deletes and reinstalls from scratch
Best forDevelopmentCI/CD pipelines
ReproducibilityMay vary if lock file updatesFully reproducible
# Development — install and potentially update lock file
npm install

# CI/CD pipeline — strict, reproducible install
npm ci

Team best practice: Use npm install during development and commit any package-lock.json changes. In CI/CD, always use npm ci to guarantee deployment consistency.

What About npx?

npx ships with NPM 5.2+ and executes package binaries without requiring global installation:

# Scaffold a new Next.js app without installing create-next-app globally
npx create-next-app my-app

# Run the project-local version of ESLint
npx eslint .

# Test your script against a specific Node.js version
npx node@18 script.js

npx lookup order:

  1. Check local node_modules/.bin/ for the binary
  2. If not found, download temporarily, execute, then clean up

This eliminates version conflicts from global installs and avoids permanently installing tools you rarely use.


CommonJS vs ES Modules

Node.js supports two module systems. Understanding the differences is essential for architecting new projects and reading open-source code.

AspectCommonJS (CJS)ES Modules (ESM)
Import syntaxconst m = require('./m')import m from './m'
Export syntaxmodule.exports = ...export default ... / export { }
LoadingSynchronousAsynchronous
Resolution timingRuntimeStatic analysis (compile time)
Tree shakingNot supportedSupported (bundlers remove unused code)
Top-level awaitNot supportedSupported
Conditional importsAnywhere (if blocks)Only via dynamic import()
Browser supportNot supported (requires bundling)Native <script type="module">
RecommendationLegacy project maintenanceUse for all new projects

How to Enable ES Modules

// package.json — add "type": "module"
{
  "name": "my-project",
  "type": "module"
}

With this setting, all .js files use ESM by default. If specific files need CommonJS, use the .cjs extension.

// ESM syntax example
import express from 'express';
import { readFile } from 'fs/promises';

export function handler(req, res) {
  // ...
}

Using .nvmrc for Team Consistency

A .nvmrc file is a simple text file placed at the project root containing the required Node.js version. When team members clone the repository, they run nvm use in the project directory, and NVM automatically reads .nvmrc and switches to the correct version.

Setting Up .nvmrc

# Create .nvmrc with the desired version
echo "20.10.0" > .nvmrc

# Or use an alias
echo "lts/iron" > .nvmrc

# Commit it to version control
git add .nvmrc

Automatic Version Switching

You can configure your shell to automatically run nvm use when you cd into a directory containing a .nvmrc file. Add this to your ~/.zshrc:

# Auto-switch Node.js version on directory change
autoload -U add-zsh-hook
load-nvmrc() {
  local nvmrc_path="$(nvm_find_nvmrc)"
  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
    if [ "$nvmrc_node_version" = "N/A" ]; then
      nvm install
    elif [ "$nvmrc_node_version" != "$(nvm version)" ]; then
      nvm use
    fi
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

.nvmrc in CI/CD

Most CI/CD platforms (GitHub Actions, GitLab CI, CircleCI) support .nvmrc natively or via setup actions:

# GitHub Actions example
- uses: actions/setup-node@v4
  with:
    node-version-file: '.nvmrc'

This ensures your CI environment runs the exact same Node.js version as your development machines — no more “works on my machine” issues.


Summary

Understanding the relationship between NVM, NPM, and Node.js is fundamental for any JavaScript developer:

  1. Install NVM first — it gives you full control over Node.js versions without permission headaches.
  2. Use NVM to install Node.js — pick the LTS version for production stability.
  3. NPM comes free with Node.js — use it to manage project dependencies, run scripts, and publish packages.
  4. Add a .nvmrc to every project for team and CI/CD consistency.
  5. Use npm ci in automated pipelines for reproducible builds.
  6. Prefer ES Modules for new projects to benefit from tree shaking and modern syntax.

By following this installation flow and understanding the distinct roles of each tool, you will avoid common pitfalls and set up a reliable, maintainable JavaScript development environment.


Further reading:

B
BenZ Software Developer

Software developer passionate about technology. Sharing programming experiences and learning notes.