Install Node.js on Ubuntu

Khimananda Oli 9 min read Virtualization
Install Node.js on Ubuntu

By Khimananda Oli | Last reviewed: August 2026

Choosing the wrong method to install Node.js on Ubuntu is a frequent source of deployment failures and security gaps in production environments. While the default APT repository offers convenience, it often provides outdated runtimes that lack critical security patches or modern language features required by current frameworks. This guide walks you through the three primary installation methods available in 2026, explaining exactly when to use each based on operational requirements rather than generic tutorials.

Start: Install Node.jsProduction Server?YESNO (Dev)NodeSource / APTSystem-wide, Stable, RootNVM / fnmPer-user, Multi-versionBest for: VPS, Docker, K8sBest for: Local Dev, Testing
Decision matrix for selecting the correct installation method when you install Node.js on Ubuntu in 2026

How do I install Node.js on Ubuntu using NodeSource for production?

The NodeSource repository is the industry standard when you need to secure a fresh VPS and deploy production applications. Unlike the default Ubuntu archives, NodeSource provides current Long Term Support (LTS) releases with verified binary compatibility. In my experience managing infrastructure for Nepal-based fintech clients and global SaaS platforms, this method reduces "works on my machine" discrepancies because the runtime matches your CI/CD pipeline exactly.

Adding the NodeSource Repository

As of 2026, NodeSource uses a simplified setup script that handles GPG key rotation automatically. Always verify the script contents before piping to bash in air-gapped or high-security environments.

# Update base packages first
sudo apt update && sudo apt upgrade -y

# Install prerequisites for HTTPS transport and CA certificates
sudo apt install -y ca-certificates curl gnupg

# Create keyrings directory if missing
sudo mkdir -p /etc/apt/keyrings

# Download and sign the NodeSource GPG key
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg

# Configure NodeSource 22.x LTS repository for Ubuntu 24.04 (noble)
NODE_MAJOR=22
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list

# Pin priority to prevent accidental downgrades during dist-upgrade
echo -e "Package: nodejs\nPin: origin deb.nodesource.com\nPin-Priority: 600" | sudo tee /etc/apt/preferences.d/nodesource

Installing and Verifying the Runtime

Once the repository is configured, installation is a single command. Note that the nodejs package from NodeSource includes npm automatically; you do not need to install it separately.

sudo apt update
sudo apt install -y nodejs

# Verify both node and npm versions
node -v
npm -v

# Confirm binary path is correct (should be /usr/bin/node)
which node

A common mistake I see in audits is skipping the verification step. If node -v returns an unexpected version, check /etc/apt/preferences.d/ for conflicting pins or stale entries in /etc/apt/sources.list.d/. For teams managing multiple servers, automate this entire block via Ansible or cloud-init to ensure idempotency across your fleet.

What is the difference between NVM, NodeSource, and default APT?

Understanding the trade-offs between installation methods prevents costly migrations later. Each approach serves a distinct operational context, and choosing incorrectly leads to either version drift in production or unnecessary friction in development workflows.

CriteriaDefault APTNodeSourceNVM / fnm
Version FreshnessOld (OS-release locked)Current LTS / LatestAny version on demand
Installation ScopeSystem-wide (/usr/bin)System-wide (/usr/bin)Per-user (~/.nvm)
Root RequiredYesYesNo
Multi-Version SupportNoNo (single version)Native switching
Production SuitabilityLow (outdated)High (stable, verified)Medium (user-space)
Docker CompatibilityPoorExcellentOverkill for containers
Uninstall ComplexitySimple (apt remove)Simple (apt remove)Manual cleanup required

In practice, I recommend NodeSource for any server that runs a single application in production. Use NVM or its faster Rust-based alternative fnm exclusively for developer workstations where engineers juggle legacy projects alongside greenfield work. The default APT package should only be used if you are building system tools that depend on the specific Node version shipped with that Ubuntu release and you accept the security maintenance burden.

How do you manage multiple Node.js versions on Ubuntu for development?

Development environments require flexibility that system-wide installs cannot provide. When you set up local development with Docker Compose, containerization solves this cleanly. However, for bare-metal development or debugging host-level issues, Node Version Manager (NVM) remains essential.

NVM (Per-User Space)~/.nvm/versions/node/v22.14.0Active via .nvmrc~/.nvm/versions/node/v20.18.3Legacy project support~/.nvm/versions/node/v18.20.8Maintenance modeNo root required • Isolated npm cachesNodeSource (System-Wide)/usr/bin/nodeSingle LTS VersionManaged by apt/dpkg⚠ Requires sudo for global installs✓ Consistent across all users✓ Ideal for systemd services
Comparison of per-user NVM isolation versus system-wide NodeSource installation paths when you install Node.js on Ubuntu

Installing NVM Safely

Always download the install script and inspect it before execution. The official installer modifies your shell profile (.bashrc, .zshrc) to load NVM lazily, which prevents shell startup latency.

# Download and run the official install script
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

# Reload shell configuration or restart terminal
source ~/.bashrc

# Verify installation
command -v nvm

Using .nvmrc for Project Consistency

Create a .nvmrc file in every project root specifying the exact Node version. This eliminates version mismatch bugs when onboarding new developers or running CI jobs.

# In project root
echo "22.14.0" > .nvmrc

# Developers then simply run:
nvm use

# Auto-switch on directory entry (add to .bashrc/.zshrc)
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

For teams prioritizing speed over NVM's feature set, consider fnm (Fast Node Manager). It is written in Rust, starts instantly, and supports .nvmrc files natively. Install it via curl -fsSL https://fnm.vercel.app/install | bash and configure shell integration similarly.

How do you secure and optimize Node.js after installation on Ubuntu?

Installation is only the first step. Production readiness requires hardening the runtime environment, configuring proper permissions, and establishing update hygiene. I have audited dozens of Ubuntu servers where Node.js was installed correctly but left dangerously exposed.

Running Node.js as a Non-Root User

Never run application code as root. Create a dedicated service account with minimal privileges. This limits blast radius if your application is compromised.

# Create a dedicated nodeapp user with no login shell
sudo useradd -r -s /bin/false -m -d /opt/nodeapp nodeapp

# Set ownership of application directory
sudo chown -R nodeapp:nodeapp /opt/nodeapp

# Example systemd unit file (/etc/systemd/system/nodeapp.service)
[Unit]
Description=Node.js Application
After=network.target

[Service]
Type=simple
User=nodeapp
Group=nodeapp
WorkingDirectory=/opt/nodeapp
ExecStart=/usr/bin/node /opt/nodeapp/server.js
Restart=on-failure
Environment=NODE_ENV=production
# Security hardening directives
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/opt/nodeapp/logs /opt/nodeapp/tmp
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Configuring Global Package Permissions

Avoid using sudo npm install -g with NodeSource installations. Instead, reconfigure npm's global prefix to a user-writable directory. This prevents permission errors and reduces the risk of accidentally installing malicious packages with root privileges.

# Create a directory for global packages
mkdir -p ~/.npm-global

# Configure npm to use the new directory
npm config set prefix '~/.npm-global'

# Add to PATH in .bashrc or .profile
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Establishing Update Cadence

Node.js LTS releases receive security updates for 30 months. Subscribe to the official Node.js security announcements RSS feed. For automated patching on Ubuntu, enable unattended-upgrades specifically for the NodeSource repository:

# /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
    "nodistro:nodistro";
};

This ensures critical CVE patches apply automatically without breaking major version compatibility. Always test patches in staging first; even minor version bumps can introduce regressions in edge cases.

1. Verify Versionnode -v matches LTS2. Create Service Useruseradd -r nodeapp3. Fix npm PrefixAvoid sudo npm -g4. SystemdHardened Unit5. Enable Automated Security Patchesunattended-upgrades + NodeSource pinningTest in staging before production rolloutProduction Ready Checklist✓ Non-root execution ✓ Writable global prefix ✓ LTS version pinned✓ Systemd hardening enabled ✓ Auto-security updates configuredMonitor CVE feeds at nodejs.org/en/blog/vulnerability
Sequential hardening workflow after you install Node.js on Ubuntu for production deployments

When should you use Snap or compile Node.js from source on Ubuntu?

Snap packages offer sandboxed isolation and automatic updates, making them suitable for desktop applications or kiosk deployments where system integration is secondary to containment. However, Snaps have slower cold-start times due to squashfs mounting and restricted filesystem access, which makes them poor candidates for high-performance web servers or CI runners where startup latency matters.

Compiling from source is rarely necessary in 2026 unless you require custom build flags (e.g., enabling experimental OpenSSL engines, linking against a specific ICU version, or patching a vulnerability before upstream release). The compilation process takes 15–30 minutes on typical VPS hardware and introduces maintenance overhead for future upgrades. Reserve this approach for specialized embedded systems or compliance-mandated builds where binary provenance must be cryptographically verified against source.

For most engineers reading this guide, the decision tree is simple: NodeSource for production servers, NVM/fnm for development machines, and avoid Snap/source builds unless you have a documented requirement that the other two methods cannot satisfy.

Next Steps After You Install Node.js on Ubuntu

Successfully installing the runtime is just the foundation. Your next priorities should be configuring reverse proxying with Nginx, setting up process management via systemd, and integrating monitoring to catch regressions early. If you are deploying a full-stack application, review our guide on setting up a LEMP stack on Ubuntu for integrated database and web server configuration. For teams adopting infrastructure-as-code, consider automating these installation steps using Ansible playbooks to ensure reproducible, auditable deployments across environments. If your architecture demands containerization instead of bare-metal installs, start with Docker fundamentals to isolate dependencies completely.

Need help architecting a production-grade Node.js deployment or auditing your existing Ubuntu infrastructure? Reach out directly to discuss your specific requirements.

Frequently Asked Questions

Use NodeSource binary distributions via their official setup script for the latest LTS version. This method provides apt-managed packages that receive automatic security updates and integrate cleanly with Ubuntu system package management tools.

Use nvm (Node Version Manager) to install and switch between multiple Node.js versions per user. Run nvm install followed by the version number, then nvm use to activate it without affecting system-wide packages or other projects.

Yes, but the default repository often contains outdated versions. For production environments in 2026, always use NodeSource or nvm to get current LTS releases with active security support and modern feature compatibility.

Run node -v and npm -v in your terminal to check installed versions. Confirm the binary path with which node to ensure you are using the expected installation source and not an old system version.

System-wide installs via apt require sudo privileges. User-level installations using nvm do not need root access and keep Node.js isolated within your home directory for safer development workflows.

If installed via NodeSource, run sudo apt update && sudo apt upgrade. For nvm users, run nvm install latest-lts to fetch the newest release and nvm alias default to set it as your primary version.

Yes, nvm allows switching between versions instantly per shell session. Each project can specify its required version in an .nvmrc file, enabling automatic version selection when entering the directory.

Global npm installs conflict with system directories when using apt-installed Node.js. Fix this by configuring npm prefix to a user-writable directory or switching to nvm, which manages global packages without root permissions.

For apt installs, run sudo apt remove nodejs npm && sudo apt autoremove. For nvm, delete the ~/.nvm directory and remove related lines from your shell profile configuration files to clean up entirely.

Choose LTS for production servers and long-term stability. Current releases offer newest features but have shorter support windows. Most Ubuntu deployments in 2026 should target the active LTS line for security patches.

Install build-essential and python3 via apt before running npm install. Native addons like sharp or bcrypt require C++ compilers and headers that are not included in minimal Ubuntu server installations by default.

Yes, both NodeSource and nvm bundle npm with Node.js. Verify compatibility by checking npm version matches your Node.js release, as mismatched versions can cause unexpected dependency resolution failures during installs.

Create a unit file in /etc/systemd/system pointing to your app entry point. Set User, WorkingDirectory, and Environment variables explicitly, then enable and start the service for persistent background execution.

Open only the specific port your application listens on using ufw allow. Never expose the Node.js debug port publicly. Reverse proxy through Nginx or Caddy to handle TLS termination and restrict direct backend access.

Check journalctl -u your-service for systemd errors and verify file permissions on your app directory. Test the command manually as the service user to isolate configuration issues from runtime environment problems.