How To Install Npm On Linux

How To Install Npm On Linux

Reading time1 min
#Development#Programming#OpenSource#Nodejs#NPM#Linux

Mastering npm Installation on Linux: Practical Engineering Guidance

Permission denied.
That’s the message many developers encounter when running npm install -g <package> on Linux. Unpacking the reasons requires looking past package manager defaults and focusing on reproducibility, version isolation, and developer efficiency.


The Core Principle

Everything starts by decoupling your Node.js/npm environment from your distribution's package manager. The majority of Linux distros ship with outdated Node and npm versions (check with apt show nodejs on Ubuntu 20.04). Relying on apt, yum, or similar leads to legacy package versions, security risks, and avoidable headaches:

$ apt-get install nodejs npm
$ node -v
v10.19.0   # ← Already unsupported
$ npm -v
6.14.4

Most CI/CD pipelines and build systems expect parity with upstream Node.js LTS releases, not whatever shipped in your distro two years ago.


Install Node.js & npm — The Portable, Idiomatic Way

Use nvm (Node Version Manager). This avoids system-wide privileges and makes version switching trivial.

Installation (nvm v0.39.5 as of June 2024):

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
export NVM_DIR="${HOME}/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

For shells like Zsh or Fish, update respective rc files to source nvm. Persistent export in .bashrc/.zshrc is standard.

Node LTS install:

nvm install --lts
nvm use --lts

Check versions:

node -v    # Expected: v18.x or v20.x, depending on upstream LTS
npm -v     # Typically npm@10.x+ as of mid-2024

Avoiding Global Permission Problems

Default behavior for npm install -g often targets /usr/lib/node_modules or /usr/local/lib/node_modules. On multi-user or rootless systems, this means instant EACCES errors:

npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /usr/local/lib/node_modules/...
npm ERR! errno -13

Always set a user directory for global npm packages. Example:

mkdir -p "${HOME}/.npm-global"
npm config set prefix "${HOME}/.npm-global"

Update your PATH:

echo 'export PATH=$HOME/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Confirmed by installing a global util (no sudo required):

npm install -g typescript
tsc --version

Note: If Node was previously installed via Snap, apt, or other system means, which node or which npm may reveal collisions. Remove old system versions to prevent PATH ambiguity. A classic case: Snap installs at /snap/bin/node often override user expectations.


Keeping npm Up to Date—Without Undermining Stability

Containerized environments sometimes hard-pin Node and npm (e.g., for legacy builds). For most individual workstations and dev machines, upgrades are safe:

npm install -g npm@latest
npm -v

Within an nvm context, upgrades apply only to the currently active version. For a clean slate or to “reset” corrupted installs, nvm install --lts --reinstall-packages-from=current replaces both node and npm cleanly. Gotcha: Some npm plugins or native extension builds may force you to purge caches or rebuild node modules (see npm rebuild).


Diagnosing Multiple Node/npm Instances

Mixed environments can introduce subtle bugs. If you ever see unpredictable npm behavior, run:

which node
which npm
whereis node
whereis npm
npm config get prefix

Table: Typical Causes of npm Issues

Error/BehaviorLikely Root Cause
EACCES permission errorsGlobal install path owned by root
npm/yarn version mismatchPATH prioritized system npm over nvm
Packages missing in $PATH~/.npm-global/bin not added to $PATH

Non-Obvious Tips & Practical Examples

  • For project-level isolation, use nvm exec lts/* npm ci in CI for full reproducibility—ensures no untracked global installs.
  • Alternative: If managing build-dependencies for Docker or containers, avoid nvm (as login shells may not source it correctly); instead, use official Node images or direct binaries from nodejs.org/dist.
  • Trade-off: Using a user-global prefix speeds up dev workflows, but on CI or production, always use local, per-project node_modules for deterministic builds.
  • Cleanup: After switching to nvm, purge old system copies to avoid future confusion:
    sudo apt-get remove nodejs npm
    sudo snap remove node --purge
    

Summary Table: Hardened npm Setup

StepCommand / ActionWhy
Isolate Node/npmnvm install --ltsAvoids old/insecure packages
User-level globalsnpm config set prefix ~/.npm-globalNo sudo for global tools
Update PATHAdd ~/.npm-global/bin to .bashrcImmediate CLI access
Upgrade npm as needednpm install -g npm@latestAccess to latest npm fixes/features
Remove system Nodeapt-get remove nodejs npmPrevents PATH ambiguity
Version diagnosticswhich node; which npm; npm config get prefixSpot errors, environment drift

Above approach eliminates most npm permission issues, maintains flexibility for multiple Node versions, and integrates well with hybrid local/cloud workflows. Realistically, sometimes pegged system-wide installations are mandated by policy—adapt accordingly but document exceptions.

For most team and solo development on Linux: use nvm, set a user global prefix, always check your PATH, and script these steps into onboarding docs for consistency.

No magic; just reliable, reproducible setups.