How to Install Node.js and npm on Fedora (System Package vs NVM)

Install Node.js and npm on Fedora via DNF for system-wide use or NVM for flexible version management.

You cloned a repository and the build failed

You ran npm install and the terminal printed npm: command not found. Or you installed Node.js, but the project demands version 18 and the system has version 20, so the build aborts with a dependency conflict. You need Node.js and npm working, but Fedora offers two paths that seem to overlap. One path uses the system package manager. The other uses a user-space tool called NVM. Picking the wrong one leads to permission errors, version mismatches, and broken scripts.

What's actually happening

Fedora separates system tools from user development tools. The system package manager provides a single, stable version of Node.js for the entire machine. This version lives in /usr/bin and is managed by dnf. It stays consistent across reboots and updates. This approach works well for simple scripts or services that run as root. It does not work well when you need multiple versions.

Development workflows often require version isolation. One project requires Node 16. Another requires Node 20. A third needs the latest LTS. Installing everything via dnf creates conflicts. You cannot have two system versions of Node.js active at the same time. NVM (Node Version Manager) solves this by managing versions per user. NVM installs files in your home directory, isolated from the system. You can switch versions instantly without affecting the OS.

NVM is not a daemon. It is a collection of shell functions. When you type nvm use 18, the function modifies your PATH variable to point to the directory containing Node 18. The shell searches PATH from left to right. By prepending the NVM path, the shell finds the NVM binary before the system binary. This mechanism means NVM only works in interactive shells. Scripts that do not source your profile will not see the NVM version. This is a design choice, not a bug. It keeps the system clean and the user in control.

Global npm packages are another source of confusion. With the system package, global installs go to /usr/lib/node_modules. You need sudo to write there. That creates permission errors when npm tries to update its own cache. NVM installs global packages in ~/.nvm/versions/node/v.../lib/node_modules. You own those files. No sudo is needed. This eliminates the permission trap that plagues many Node.js setups.

dnf upgrade --refresh is the normal weekly maintenance command for system packages. It refreshes metadata and applies updates. NVM versions do not update automatically. You must run nvm install --lts to get a new version. The system package manager handles OS dependencies. npm handles application dependencies. Keep them separate. Mixing them causes drift and breakage.

The fix or how-to

Here's how to install the stable system-wide version using dnf.

sudo dnf install nodejs npm # Install the system Node.js and npm packages
# --refresh ensures you get the latest metadata before installing
# This places binaries in /usr/bin, available to all users
# The system package includes a curated version of Node.js

Here's how to set up NVM for per-user version management.

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Download and execute the NVM installation script
# The script appends initialization code to your shell profile
source ~/.bashrc # Reload the shell configuration to activate NVM
# NVM is now available in the current session
nvm install --lts # Install the latest Long Term Support version of Node
# This downloads the binary and sets it as the default for your user

If you use zsh instead of bash, source the correct profile.

source ~/.zshrc # Reload zsh configuration after NVM install
# NVM detects the shell and updates the appropriate profile file

NVM respects .nvmrc files in project directories. This keeps your environment consistent across machines.

cd /path/to/project # Navigate to the project directory
nvm use # Switch to the version specified in .nvmrc
# NVM reads the file and updates PATH automatically
# If the version is not installed, NVM prompts you to install it

Reboot is rarely needed for Node. A new terminal session is usually enough.

Verify it worked

Here's how to confirm the installation and check which version is active.

node --version # Print the active Node.js version
npm --version # Print the active npm version
which node # Show the full path to the node binary
# Verify the path points to /usr/bin for system or ~/.nvm for NVM

Here's how to inspect where global packages will install.

npm config get prefix # Show the directory for global npm packages
# With NVM, this points to your user directory
# With system package, this points to /usr/lib
# This determines whether you need sudo for global installs

Trust the path, not the version number. The path tells you which binary is actually running.

Common pitfalls and what the error looks like

The sudo trap is the most common mistake with NVM. Users install NVM, then try to run sudo npm install -g. This breaks permissions because root writes files that the user owns. NVM manages files in the home directory. Root should not touch them.

npm ERR! code EACCES
npm ERR! syscall access
npm ERR! path /home/user/.nvm/versions/node/v20.11.0/lib/node_modules
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, access '/home/user/.nvm/versions/node/v20.11.0/lib/node_modules'

Never use sudo with NVM. If a package requires root privileges, the package is misconfigured. Run npm install without sudo. If you see permission errors, check the ownership of ~/.nvm.

Version mismatches appear when the system has one version and the project needs another. The error mentions ERESOLVE and lists the found version versus the required peer dependency.

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! Found: node@20.11.0
npm ERR! node_modules/node
npm ERR!   node@"20.11.0" from the root project
npm ERR! Could not resolve dependency:
npm ERR! peer node@"^18.0.0" from some-package@1.0.0

Switch versions with NVM. Run nvm install 18 and then nvm use 18. The build will proceed. If you are using the system package, you cannot switch versions easily. You must uninstall the system package and use NVM, or accept the version Fedora provides.

Scripts that fail to find nvm usually lack shell sourcing. Cron jobs, systemd services, and CI runners do not source ~/.bashrc. They run in a clean environment. If a script relies on NVM, it must source the NVM script explicitly.

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Source NVM in the script
nvm use 18 # Switch to the required version
node app.js # Run the application

Never use sudo with NVM. You own the files; root is the problem, not the solution.

When to use this vs alternatives

Use the system package when you need Node.js for a simple script or a service that runs as root. Use the system package when you are managing a server and want updates handled by dnf upgrade. Use NVM when you are a developer working on multiple projects with different Node requirements. Use NVM when you need to test code against older versions without affecting the system. Use NVM when you want to install global npm packages without sudo. Stay on the system package if you only ever run one version and never touch global node_modules.

Where to go next