When you start working with modern JavaScript tooling, you immediately run into a bunch of names:
- Node.js
- nvm
- npm
- npx
- Yarn
- Corepack
Docs casually say things like:
- “Install Node with nvm”
- “Use npm or Yarn to install dependencies”
- “Run the generator with npx”
- “Use Corepack with Yarn 4”
- “Backstage recommends Yarn + Corepack”
If you only want to run a project or set up something like Backstage, this can feel unnecessarily complicated.
This post is a relationship map:
- What each tool actually is
- How they relate to each other
- Which pieces you really need
- How to combine nvm + Node + npm + Yarn + Corepack in a sane way
- Big Picture: Who Manages What?
If you remember only one thing, remember this:
There are layers.
nvm manages Node versions.
Each Node version ships with npm and npx. Newer Node versions also ship with Corepack.
Corepack manages Yarn/pnpm versions.
npm / Yarn / pnpm manage your actual packages.
A quick summary table:
| Name | Type | Main Role | Typical Commands |
|---|---|---|---|
| nvm | Node version manager | Install and switch between Node versions | nvm install 22, nvm use --lts |
| Node.js | Runtime | Run JavaScript/TypeScript outside the browser | node app.js |
| npm | Package manager | Install and manage Node packages | npm install, npm install -g typescript |
| npx | CLI runner (uses npm under the hood) | Download and execute CLI tools on demand | npx @backstage/create-app@latest |
| Yarn | Package manager | Alternative to npm; often used in modern toolchains | yarn install, yarn dev, yarn build |
| Corepack | Package-manager manager | Ship and pin Yarn/pnpm versions per project | corepack enable, then just yarn / pnpm |
- Hierarchy View: Like Expanding Folders in a File Explorer
An easy way to visualize the relationships is to imagine a file explorer tree.
Conceptually:
nvm
├─ Node v18.x
│ ├─ npm
│ │ ├─ Global packages (for Node v18.x)
│ │ │ ├─ typescript
│ │ │ └─ eslint
│ │ └─ Project packages (per-project node_modules)
│ │ ├─ /project-a/node_modules
│ │ └─ /project-b/node_modules
│ ├─ npx
│ │ └─ CLI runs (each maps to some package@version)
│ │ ├─ npx @backstage/create-app@latest
│ │ └─ npx create-react-app@5
│ └─ Corepack
│ ├─ yarn@4.5.0 (for Project A, from packageManager)
│ │ └─ Packages installed via Yarn in Project A
│ ├─ yarn@4.4.1 (for Project B)
│ │ └─ Packages installed via Yarn in Project B
│ └─ pnpm@9.x (for any project using pnpm)
│ └─ Packages installed via pnpm
│
└─ Node v22.x
├─ npm
├─ npx
└─ Corepack
└─ (its own Yarn/pnpm versions & caches)
In words:
- nvm expands into multiple Node versions (v18, v20, v22, …).
- Each Node version expands into:
- npm – manages packages (global + per-project)
- npx – runs CLI tools (mapping to specific packages/versions)
- Corepack – manages concrete Yarn/pnpm versions
- Corepack expands into:
yarn@4.5.0,yarn@4.4.1,pnpm@9.x, …
- Each specific Yarn/pnpm version expands into:
- The packages it installs for the projects that use it.
So the hierarchy is:
nvm → Node versions → npm / npx / Corepack →
Corepack → Yarn / pnpm versions → dependencies in each project.
Note: In reality, when you run which yarn, you’ll see a single path like~/.nvm/versions/node/v20.19.6/bin/yarn.
That file is a Corepack shim, not “the Yarn binary itself”. Corepack uses that shim to dispatch to different Yarn versions (e.g. yarn@4.5.0, yarn@4.4.1) depending on what each project declares in its packageManager field.
With this picture in mind, the rest of the details become easier to digest.
- nvm: Node Version Manager (and How to Install It)
We start at the top of the tree: nvm.
What nvm Does
nvm (Node Version Manager) is not part of Node. It’s a separate tool that:
- Installs Node into
~/.nvm/versions/node/... - Lets you easily install multiple Node versions
- Lets you switch Node versions in your shell
- Keeps “global” npm installs isolated per Node version
Typical commands:
# Install specific Node versions
nvm install 22
nvm install --lts # latest LTS
nvm install --lts=iron # specific LTS codename
# Switch version in current shell
nvm use 22
nvm use --lts
# Set default Node for new shells
nvm alias default 22
nvm alias default --lts
With nvm:
npm install -ginstalls inside the currently active Node version’s directory.node -vandnpm -vchange when you runnvm use ....
In the file-explorer analogy:
nvm
├─ Node v18.x
└─ Node v22.x
Key idea:
nvm sits at the top. It decides which Node version (and therefore which npm/npx/Corepack instance) your shell is using.
Installing nvm (Quick)
You can install nvm with the official install script, for example:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
Then reload your shell config (depending on what you use):
# For Bash
source ~/.bashrc
# For Zsh
source ~/.zshrc
Verify that nvm is available:
nvm --version
From here on, all Node-related commands in this post assume you have nvm working.
- Node.js: The Runtime Inside Each nvm Node
Under each Node version folder in that tree, you have Node.js itself.
Node.js is the runtime that executes JavaScript (and transpiled TypeScript) outside the browser.
- Embeds the V8 engine (from Chrome).
- Provides server-side APIs like
fs,http,net, etc. - When installed via nvm, each version lives in its own directory and comes with:
- npm – the default package manager.
- npx – the CLI runner (bundled with npm).
- Corepack – in newer Node versions, for Yarn/pnpm management.
Example:
node app.js
This runs a JavaScript file with the currently active Node version (selected by nvm).
Within the tree:
nvm
└─ Node v22.x
├─ node (the runtime)
├─ npm
├─ npx
└─ Corepack
From here down, everything you do (installing packages, running CLIs, using Yarn via Corepack) happens inside the context of this Node version.
- npm: The Default Package Manager
npm is the default package manager that comes bundled with Node.
It has two main jobs:
- Install dependencies into your project
- Install CLI tools (locally for the project, or “global” per Node version)
Common patterns:
# Local (project-level) install – creates node_modules/ in this directory
npm install # read package.json dependencies
npm install lodash # add lodash to dependencies
# Global install (scoped to current Node version when using nvm)
npm install -g typescript
tsc --version
Where things go:
- Local install →
./node_modulesand./node_modules/.bin - Global install (with nvm) →
~/.nvm/versions/node/vXX.YY.ZZ/lib/node_modules/...
plus symlinks in~/.nvm/versions/node/vXX.YY.ZZ/bin
In the tree:
Node v22.x
└─ npm
├─ Global packages
│ ├─ typescript
│ └─ eslint
└─ Project packages
├─ /project-a/node_modules
└─ /project-b/node_modules
So with nvm:
- You do not pollute system-wide directories like
/usr/local/lib/node_modules. - “Global” npm tools are tied to that Node version.
- npx: “Download and Run This CLI Once”
npx is a CLI runner built on top of npm.
Instead of:
npm install -g some-cli
some-cli init
you can run:
npx some-cli init
What happens when you run npx some-cli:
- Look for
some-cliin:- local
node_modules/.bin - global npm installs for the current Node version
- local
- If not found, download
some-clifrom the npm registry to a cache - Run its
binscript once - You don’t keep it as a permanent global install
Example with Backstage:
npx @backstage/create-app@latest
This:
- Downloads
@backstage/create-app(if necessary) - Runs its CLI to scaffold a new Backstage app
- You don’t have to
npm install -g @backstage/create-app
In the tree:
Node v22.x
└─ npx
└─ CLI runs (mapped to package@version)
├─ npx @backstage/create-app@latest
└─ npx create-react-app@5
Key idea:
npm is for installing packages.
npx is for executing CLI packages on demand (often without global install).
- Yarn: An Alternative Package Manager
Yarn is a package manager for Node projects, originally created to improve npm’s weaknesses in speed and determinism.
Key points:
- Reads
package.jsonlike npm. - Uses its own lockfile (
yarn.lock). - Commands are similar but not identical:
# Install dependencies
yarn install
# Add dependencies
yarn add lodash
yarn add --dev typescript
# Run scripts from package.json
yarn dev
yarn build
yarn test
Two important “eras” of Yarn:
- Yarn 1 (“Classic”) – more like a traditional npm alternative.
- Yarn 2+ (Berry, v3, v4, …) – modern architecture, more features (Plug’n’Play, etc.), different behavior in some areas.
Many modern toolchains (including Backstage) expect Yarn Berry (v3/v4), not Yarn 1.
Historically people installed Yarn globally:
npm install -g yarn
yarn -v
With Corepack, that’s no longer the preferred default.
- Corepack: Manager for Yarn and pnpm
Corepack is bundled with newer Node versions. Its job is to manage other package managers, such as:
- Yarn
- pnpm
Its goals:
- Avoid manual global installs like
npm install -g yarn. - Use the exact package manager version that the project asks for.
Projects can declare their package manager in package.json:
{
"name": "my-app",
"version": "1.0.0",
"packageManager": "yarn@4.5.0"
}
With Corepack enabled, when you run yarn inside this project:
- Corepack reads
"packageManager": "yarn@4.5.0". - If it doesn’t have Yarn 4.5.0 yet, it downloads and caches it.
- It runs Yarn 4.5.0 to handle commands for this project.
You don’t manually install Yarn at all.
Basic Corepack usage:
# Enable shims for yarn / pnpm (once per Node version)
corepack enable
# (Optional) Pre-fetch a Yarn version for general use:
corepack prepare yarn@stable --activate
After corepack enable, the yarn you see from which is the Corepack shim:
which yarn
# /home/ubuntu/.nvm/versions/node/v20.19.6/bin/yarn
That path is just the launcher. Corepack uses it to decide which Yarn version to run based on the current project:
- In a project with
"packageManager": "yarn@4.5.0"→yarn -vshows 4.5.0 - In another project with
"packageManager": "yarn@4.4.1"→yarn -vshows 4.4.1
Same which yarn, different Yarn versions behind the scenes.
Important:
Corepack does not manage npm. npm is still bundled directly with Node.
Did this guide save you time?
Support this site