Node.js on Ubuntu: Fast, Repeatable, and Robust Installation
Node.js drives many production platforms: APIs, web backends, and build pipelines. On Ubuntu, a messy Node.js setup leads to versioning headaches, permissions trouble, and CI failures. Clean install matters. So here's the workflow used by teams that need durable and up-to-date dev environments.
1. Prep Your Base System
Always begin by updating your system metadata and dependencies. Security patches land daily; stale packages create subtle breakages:
sudo apt update
sudo apt upgrade -y
Note: Major release upgrades (e.g., Ubuntu 20.04 → 22.04) might deprecate older Node binaries. Double-check /usr/bin/node
after an OS upgrade.
2. Select an Installation Method
- NodeSource PPA: Stable, repeatable, single-version installs. Good for prod servers and consistent developer environments.
- nvm (Node Version Manager): Multiple Node.js versions side by side. Essential for polyglot projects or legacy app support.
Decision point: If you need only one version—and want system scripts and services to pick it up—use NodeSource. If you actively switch between major versions, use nvm.
2A. NodeSource PPA Approach
NodeSource delivers signed, up-to-date Node.js binaries for Ubuntu. As of June 2024, Node.js 20.x LTS is common:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
Verify version:
node -v # Should be v20.x.x
npm -v # As shipped with corresponding Node version
Gotcha: The package also includes npm; no need for a separate install.
Uninstalling: If you ever need to wipe Node from the system:
sudo apt-get remove nodejs npm -y
sudo apt autoremove -y
This does not touch files in /usr/local
or nvm-managed installs.
2B. nvm for Multi-Version Flexibility
When project A requires Node 18.x, and project B is stuck on Node 16.x, nvm handles the context switch. It works entirely in user-space, avoiding root privs and system conflicts.
Install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
exec $SHELL
or reload configuration:
source ~/.bashrc
Add recent Node releases (example):
nvm install 20
nvm install 18
nvm alias default 20
Switch versions on the fly for a terminal session:
nvm use 18
Check active binaries:
which node
# Should be under ~/.nvm/versions/node/
Note: Systemd services do not see user-level nvm unless configured as that user.
3. Validate npm and the Compiler Toolchain
Many modern JavaScript libraries rely on native addons (node-gyp
, C++ bindings, etc). Missing build tools cause this error during npm install
:
gyp ERR! stack Error: not found: make
gyp ERR! stack at getNotFoundError (/usr/lib/node_modules/npm/node_modules/which/which.js:13:12)
Install the essentials:
sudo apt-get install build-essential libssl-dev -y
Test with an actual package:
npm install -g node-gyp
node-gyp --version
If this fails, investigate environment and permissions.
4. Practical Example: Minimal Static Server
Confirm the install by serving a local directory (works via either nvm- or PPA-installed Node):
npx http-server .
Open http://localhost:8080
in a browser. For a non-global package approach, leverage npx
so you avoid system pollution.
5. Non-Obvious Tips for Real-World Teams
-
Place
.nvmrc
files with version numbers in repo roots; enablesnvm use
to auto-select correct Node. -
For Dockerized workflows, prefer NodeSource or the official
node
images, not nvm. -
Adjust npm default behaviors or proxy settings via
~/.npmrc
:save-exact=true strict-ssl=false
-
Set
$PATH
explicitly for non-interactive SSH scripts (e.g., within CI runners) when using nvm. -
Don’t use
sudo
for npm installs under nvm. Under NodeSource installs, only usesudo
with intention (global dev tools).
6. Troubleshooting Patterns
Symptom | Underlying Issue | Solution |
---|---|---|
node: command not found | PATH misconfiguration, binary missing | Reinstall via method above |
npm ERR! code EACCES | Permissions problem with node_modules | Use nvm / fix ownership |
Wrong Node version in CI | CI image, not local env, controls Node | Specify in pipeline config |
Error: Cannot find module ... | Missed global vs. local install | Use npx or correct install |
Note: Manually mixing apt, nvm, and source builds in one environment will eventually produce hard-to-debug issues. Stick to one strategy per workspace or responsibility boundary.
Final Observations
Most Node.js “weirdness” in Ubuntu comes from version churn or mismanaged permissions. A disciplined approach — pick an install strategy, automate verification (node -v
, native build test), and document expectations (e.g., .nvmrc, package lock files) — outshines any “magic bullet.”
Alternatives exist (like building from source or using Snap), but they rarely justify the extra variables unless hard constraints exist (e.g., ARM builds, legacy kernels).
For further process hardening: Integrate your Node install and test checks into CI pipelines and pre-commit hooks. If the workflow above saves you troubleshooting hours, audit it annually: Node.js evolves, and so do your requirements.