How to Install Node.js on Linux with nvm

Tested on: Ubuntu 26.04, Fedora 44, Arch Linux — June 2026
There are four ways to install Node.js on Linux, and the one you choose matters more than most guides admit. The system package manager (apt, dnf, pacman) installs an old version. The official NodeSource repo gives you current versions. nvm (Node Version Manager) gives you everything: install any version, switch between them instantly, and avoid the permission problems that plague global npm installs. This guide teaches nvm as the primary approach, with alternatives for servers and containers.
- Which Installation Method to Choose
- Method 1: Install Node.js with nvm (Recommended)
- Method 2: NodeSource Repository (for Servers)
- npm: Managing Packages
- Run Your First Node.js Application
- Run Node.js Apps in Production with PM2
- Using npx: Run Packages Without Installing
- Environment Variables and .env Files
- Troubleshooting
Which Installation Method to Choose
| Method | Node version | Switch versions | Best for |
|---|---|---|---|
| nvm | Any version | Yes | Developers (recommended) |
| NodeSource repo | Current LTS/latest | No (one at a time) | Servers, single-version setups |
| apt/dnf/pacman | Old (distro package) | No | Avoid for development |
| Snap/Flatpak | Relatively current | No | Quick testing only |
Method 1: Install Node.js with nvm (Recommended)
nvm installs Node.js in your home directory — no sudo required for installing packages. It works identically on Ubuntu, Debian, Fedora, Arch, and any other Linux distro.
Install nvm
# Download and run the nvm install script (works on all distros)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# The script adds this to your ~/.bashrc or ~/.zshrc automatically:
# export NVM_DIR="$HOME/.nvm"
# [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
# Reload your shell config
source ~/.bashrc
# or for zsh:
source ~/.zshrc
# Verify nvm is installed
nvm --versionInstall Node.js via nvm
# Install the latest LTS version (recommended for most projects)
nvm install --lts
# Install the latest current version
nvm install node
# Install a specific version
nvm install 20
nvm install 18.20.3
# List all available versions
nvm ls-remote --lts | tail -20
# List installed versions
nvm ls
# Switch between installed versions
nvm use 20
nvm use 18
# Set a default version (used in new terminal sessions)
nvm alias default 20
# Check active version
node --version
npm --versionPer-Project Node Version (.nvmrc)
Pin a Node.js version to a project using a .nvmrc file:
# Create .nvmrc in your project root
echo "20" > .nvmrc
# nvm will use this version automatically when you enter the directory
nvm use
# Found '/home/user/myproject/.nvmrc' with version <20>
# Now using node v20.15.1
# Add to ~/.zshrc to auto-switch on directory change:
autoload -U add-zsh-hook
load-nvmrc() {
local nvmrc_path
nvmrc_path="$(nvm_find_nvmrc)"
if [ -n "$nvmrc_path" ]; then
nvm use
fi
}
add-zsh-hook chpwd load-nvmrcMethod 2: NodeSource Repository (for Servers)
For production servers where you need a specific version without nvm's shell integration overhead:
# Ubuntu/Debian — Node.js 20 LTS from NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install nodejs -y
# Fedora/RHEL
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install nodejs -y
# Arch Linux (current version in official repos)
sudo pacman -S nodejs npm
# Verify
node --version
npm --versionnpm: Managing Packages
Essential npm Commands
# Initialize a new project
mkdir myproject && cd myproject
npm init -y # Creates package.json with defaults
# Install a dependency
npm install express
# Install a dev dependency (not needed in production)
npm install --save-dev jest
# Install globally (CLI tools)
npm install -g typescript
npm install -g pm2
# List installed packages
npm list
# Update packages
npm update
# Remove a package
npm uninstall express
# Run a script from package.json
npm run build
npm test
npm startFix Global Package Permissions (Without nvm)
If you installed Node via the system package manager and get "permission denied" on npm install -g, fix it by changing npm's global directory to your home folder:
# Create a directory for global packages
mkdir -p ~/.npm-global
# Configure npm to use it
npm config set prefix '~/.npm-global'
# Add to ~/.bashrc or ~/.profile
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# Now global installs work without sudo
npm install -g typescriptWith nvm, this is not needed — nvm already installs Node in your home directory and global packages work without sudo by default.
Run Your First Node.js Application
# Create a simple HTTP server
cat > server.js << 'EOF'
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from Node.js on Linux!
');
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
EOF
# Run it
node server.js
# Test in another terminal
curl http://localhost:3000Run Node.js Apps in Production with PM2
PM2 is a process manager for Node.js that keeps your app running after crashes and restarts it on system reboot:
# Install PM2 globally
npm install -g pm2
# Start your application
pm2 start server.js --name my-app
# View running apps
pm2 list
# View real-time logs
pm2 logs my-app
# Restart / stop / delete
pm2 restart my-app
pm2 stop my-app
pm2 delete my-app
# Auto-start on system reboot
pm2 startup
# Run the command it outputs (sudo systemctl enable pm2-user)
pm2 save # Save current process listUsing npx: Run Packages Without Installing
# Run a CLI tool without installing it globally
npx create-react-app my-react-app
npx create-next-app@latest my-next-app
# Run a specific version
npx node@18 server.js
# Check what npx would run
npx --dry-run typescriptEnvironment Variables and .env Files
# Set environment variables for a single run
PORT=8080 NODE_ENV=production node server.js
# Use a .env file with dotenv package
npm install dotenv
# .env file:
PORT=3000
DATABASE_URL=postgres://localhost/mydb
SECRET_KEY=mysecretkey
# In your code:
require('dotenv').config();
console.log(process.env.PORT); // 3000
# Never commit .env to git
echo ".env" >> .gitignoreTroubleshooting
nvm: command not found after install
# The install script added nvm to ~/.bashrc but your shell hasn't reloaded
source ~/.bashrc
# If using zsh:
source ~/.zshrc
# If still not found, check if nvm.sh exists:
ls ~/.nvm/nvm.sh
# And manually add to your shell config:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"node: command not found (after nvm install)
# You installed nvm but haven't installed Node yet
nvm install --lts
nvm use --lts
# Verify
node --versionEACCES permission denied on npm install -g
This only happens with system-installed Node.js. Either switch to nvm (recommended) or change the npm prefix directory (see the permissions fix section above). Never use sudo npm install -g — it creates files owned by root that break future npm operations.
Port already in use (EADDRINUSE)
# Find what's using port 3000
ss -tlnp | grep 3000
# or
lsof -i :3000
# Kill it
kill $(lsof -t -i:3000)
# Or use a different port
PORT=3001 node server.jsnvm is the right tool for developers: install any Node version, switch per project, no sudo for global packages. NodeSource repos suit servers where you want a predictable version managed by the system package manager. Choose based on whether you're doing development or running production workloads.
