Linux Tutorials

Install Node.js and npm on Fedora 45 / 44: Pick 22, 24 or 26

Run sudo dnf install nodejs on Fedora 45 and you get Node.js 22, a line that only receives critical and security fixes now. Node 24 and Node 26 sit in the same Fedora repository under their own package names, so the version you end up with depends on which name you type. The first decision is the release line, not the install method.

Original content from computingforgeeks.com - post 35967

This guide shows you how to install Node.js and npm on Fedora from the official repositories and make one version the default while keeping the others. It also fixes the npm EACCES error and covers fnm and NodeSource for when the Fedora packages fall behind. Every command was run on Fedora 45 and smoke-tested on Fedora 44 in October 2026. Fedora 44 has no Node 26 packages and packages Node 22 slightly differently, and the sections below point out where that matters.

Choose a Node.js version for Fedora

Install Node 24 from the Fedora repositories unless something forces your hand. It keeps security support until April 2028, both Fedora 45 and Fedora 44 ship it, and it moves from Active LTS to maintenance on October 20, 2026, which changes nothing for a running app. Node 26 takes over as the Active LTS on October 28, 2026, and it is the line to start a new long-lived project on.

Get Node 26 from fnm or NodeSource rather than Fedora for now, because Fedora’s nodejs26 was thirteen releases behind upstream when we tested (26.3.1 against 26.12.0). Fedora’s nodejs24 also missed July’s security release, but it trails by five releases rather than thirteen, and it is the line both Fedora releases carry. Node 22 only makes sense for an app that is already pinned to it, because it reaches end of life in April 2027. Dates come from the Node.js release schedule, and the package versions are what the Fedora 45 repository held when we tested:

Fedora packageVersion on Fedora 45Upstream statusEnd of life
nodejs22 (pulled in by nodejs)22.23.1Maintenance LTS since 2025-10-212027-04-30
nodejs2424.18.0Active LTS, maintenance from 2026-10-202028-04-30
nodejs26 (Fedora 45 only)26.3.1Current, LTS from 2026-10-282029-04-30

The plain nodejs package is the trap. On Fedora 45 it’s a metapackage whose only job is to require nodejs22, and its summary calls it a “rolling stream”, so expect it to follow a newer line in a later Fedora release without asking you. You can see the dependency before installing anything:

dnf repoquery --requires nodejs

It resolves to the Node 22 package and nothing else, which is how a fresh install ends up on a maintenance-only line.

nodejs22 = 1:22.23.1-4.fc45

On Fedora 44 the same name is provided by nodejs22 directly instead of a separate metapackage, and the choice is between Node 20, 22 and 24. The install and switching commands below work on both releases, but the exact packages dnf removes during a switch differ. Old guides that tell you to run dnf module enable nodejs:22 are out of date. Fedora dropped modular repositories, and on Fedora 45 dnf module list nodejs answers “No matches found: no module streams exist.”

Install Node.js 24 with dnf

Each Node line on Fedora is split into several packages so that several lines can live side by side. These are the ones that matter, and only the two -bin packages touch the plain node command:

  • nodejs24 and nodejs24-libs: the runtime as /usr/bin/node-24
  • nodejs24-npm: npm as npm-24 and npx-24
  • nodejs24-bin: the /usr/bin/node symlink
  • nodejs24-npm-bin: the npm and npx symlinks

Name the two -bin packages when you want Node 24 to be the default, and dnf pulls in the rest as dependencies.

sudo dnf install nodejs24-bin nodejs24-npm-bin

By default dnf also pulls in two weak dependencies, the API docs (53 MiB installed) and nodejs24-full-i18n (32 MiB), the ICU data that formats dates and numbers in non-English locales. On a server you can skip both, which keeps the install to five packages and a 21 MiB download:

sudo dnf install --setopt=install_weak_deps=False nodejs24-bin nodejs24-npm-bin

Only five packages land, and the runtime library is the heavy one.

Installing:
 nodejs24-bin     noarch 1:24.18.0-4.fc45           fedora     154.0 KiB
 nodejs24-npm-bin noarch 2:11.16.0-1.24.18.0.4.fc45 fedora      13.0 KiB
 nodejs24         x86_64 1:24.18.0-4.fc45           fedora     313.3 KiB
 nodejs24-libs    x86_64 1:24.18.0-4.fc45           fedora      62.8 MiB
 nodejs24-npm     noarch 2:11.16.0-1.24.18.0.4.fc45 fedora       8.8 MiB
 Installing:         5 packages
Total size of inbound packages is 21 MiB. Need to download 21 MiB.
Complete!

Keep the i18n package if your app renders anything for users outside English locales. We removed it on the test VM and asked Node 24 for a German month name: with the package it printed “Oktober”, without it “October”, and nothing logged a warning. That is the kind of bug you only notice in production. Confirm the runtime and npm versions.

node --version
npm --version

Node 24 ships with npm 11.

v24.18.0
11.16.0

Switch the default node between versions

Because the versioned packages do not fight over /usr/bin/node, you can keep Node 22 for an old service and Node 26 for testing on the same machine. Install the extra lines by their base package names, which skips the -bin symlinks and leaves your default alone:

sudo dnf install nodejs22 nodejs22-npm nodejs26 nodejs26-npm

Each line now answers to its own command (node-22, node-26, npm-26), which is handy in scripts and CI jobs that must not depend on whatever the default happens to be. Changing the default is different, because only one package may own the unversioned symlinks. If you started from the plain nodejs package, asking for another -bin package fails with a conflict:

Failed to resolve the transaction:
Problem 1: problem with installed package
  - installed package nodejs-1:22.23.1-4.fc45.x86_64 conflicts with alternative-for(nodejs-bin) provided by nodejs24-bin-1:24.18.0-4.fc45.noarch from fedora
  - package nodejs-1:22.23.1-4.fc45.x86_64 from fedora conflicts with alternative-for(nodejs-bin) provided by nodejs24-bin-1:24.18.0-4.fc45.noarch from fedora
  - conflicting requests

Add --allowerasing so dnf can swap the symlink owners in one transaction. On Fedora 45 it removes only nodejs and nodejs-npm, the two tiny packages that held the symlinks, and leaves nodejs22 installed and working as node-22. Read the removal list before you confirm on Fedora 44, where the symlinks belong to Node 22’s own packages:

sudo dnf install --allowerasing nodejs24-bin nodejs24-npm-bin

The same command with nodejs26-bin nodejs26-npm-bin moves the default to Node 26, and naming the 24 packages again moves it back. The result with all three lines installed and Node 24 as the default looks like this:

Node.js 22, 24 and 26 installed side by side on Fedora 45 with node pointing to 24

Check ls -l /usr/bin/node whenever a tool reports a different Node version than you expect. The symlink target tells you which -bin package won, and it is the quickest way to tell a Fedora default apart from a version manager that has put its own node earlier in your PATH.

Fix npm EACCES errors on global installs

A Fedora-packaged npm installs global packages under /usr/local, which your user can’t write to, so the first npm install -g fails with a permission error:

npm error code EACCES
npm error syscall mkdir
npm error path /usr/local/lib/node_modules
npm error errno -13
npm error Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules'

Don’t answer it with sudo npm install -g. That runs every package’s install scripts as root and leaves root-owned files that the next non-root npm run trips over. Point npm’s global prefix at your home directory instead. Fedora’s default shell profile already puts ~/.local/bin on your PATH, so the tools work right away:

npm config set prefix ~/.local
npm install -g typescript

The setting lands in ~/.npmrc. Check that the TypeScript compiler is on your path without sudo:

command -v tsc
tsc --version

It resolves to your home directory:

/home/josphat/.local/bin/tsc
Version 7.0.2

If your project uses another package manager, the Fedora repositories carry the common ones as separate packages. Corepack is not bundled with Fedora’s Node packages, and upstream stopped bundling it with Node 25, so the corepack enable step in many READMEs fails on Fedora’s packages and on any Node 26 until you install it:

  • pnpm: version 10.33 on Fedora 45
  • yarnpkg: Yarn classic, version 1.22
  • nodejs-corepack: Corepack 0.36.0, for Yarn 4 and pinned pnpm

All three require /usr/bin/node, and pnpm and Yarn also set a minimum Node version, so they follow whichever line you made the default. On our Node 24 machine sudo dnf install pnpm added a single package, and nodejs-corepack resolved to a single package too. Corepack also asks for the generic nodejs capability, which nodejs22 provided there, so on a machine without Node 22 check what dnf wants to pull in before you confirm.

A project that pins Yarn 4 through its packageManager field needs Corepack either way. The official Node 24 build that fnm installs below still includes it. On an fnm or NodeSource Node 26, run npm install -g corepack instead, which put Corepack 0.36.0 in ~/.local/bin on our VM. It also adds pnpm, yarn and yarnpkg shims there, which take precedence over the Fedora packages above, so pick one route per machine and remove any globally installed pnpm or yarn first.

Manage per-project Node versions with fnm

The Fedora packages give you one default and a versioned command per line, which is fine on a server. On a laptop where one repo wants Node 22 and the next wants 24, a version manager that switches automatically on cd saves you from typing node-22 everywhere. We use fnm for that. It isn’t in the Fedora repositories, so it comes from its own install script, which needs unzip, downloads one binary into ~/.local/share/fnm and appends a block to ~/.bashrc:

sudo dnf install unzip
curl -fsSL https://fnm.vercel.app/install | bash

The block it writes loads fnm but doesn’t switch versions when you change directory, so a project’s version file would sit there unused. Add --use-on-cd so a version file takes effect as soon as you enter the project, and --version-file-strategy=recursive, which fnm’s own docs recommend, so leaving the project puts you back on your default. Then confirm the line changed and reload the shell:

sed -i "s|eval \"\$(fnm env --shell bash)\"|eval \"\$(fnm env --use-on-cd --version-file-strategy=recursive --shell bash)\"|" ~/.bashrc
grep "fnm env" ~/.bashrc
source ~/.bashrc

The grep should print the line with both flags. If it still shows the bare fnm env --shell bash, a newer installer wrote a different line, so edit ~/.bashrc by hand. Now install Node 24 and an older line, make 24 the default, then list what fnm manages. Name the line rather than using fnm install --lts, which follows whatever the current LTS is and switches to Node 26 on October 28, 2026.

fnm install 24
fnm install 22
fnm default 24
fnm list

fnm pulls official builds from nodejs.org rather than the Fedora packages. The system entry is the Fedora-packaged default it can fall back to, and default marks the line every new shell starts on:

* v22.23.3
* v24.22.0 default
* system

Look at the Node 24 number. fnm installed 24.22.0 while the Fedora repository still carried 24.18.0, five releases behind upstream on the day we tested. One of the five, 24.18.1 from July 28, 2026, was a security release. That lag is the strongest argument for a version manager on a developer machine that runs untrusted dependencies. Pin a project to a line by dropping a .node-version file in its root (fnm also reads .nvmrc):

mkdir -p ~/legacy-app
echo 22 > ~/legacy-app/.node-version

Check both directions in an interactive shell, because the way back is where the two strategies differ:

cd ~/legacy-app
node --version
cd ~
node --version

Entering the project switches to Node 22, and leaving it switches back to the default:

Using Node v22.23.3
v22.23.3
Using Node v24.22.0
v24.22.0

We first ran with --use-on-cd alone, and there cd ~ kept Node 22 until we entered another project or opened a new shell. That is the default local strategy, and it is how one project’s runtime ends up running commands in the next.

Each fnm version takes about 200 MB in your home directory (199 MB for 22 and 204 MB for 24 here), and fnm’s node shadows the Fedora one in every shell that loads ~/.bashrc. The ~/.npmrc prefix from the previous section applies to fnm’s npm as well, so global tools in ~/.local are shared by every Node line. Systemd services don’t load ~/.bashrc, which is why the service at the end of this guide calls a Fedora binary by its full path. If the same laptop also needs Python, Go and Rust, the polyglot Fedora dev environment sets those up next to Node.

Node 26 from fnm needs one library that Node 22 and 24 don’t. On our VM, after removing Fedora’s Node packages (which had pulled it in), fnm install 26 succeeded but every node call failed. A minimal Fedora 45 install doesn’t ship the library either, so expect the same on a fresh server or cloud image:

node: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory

Install it from the Fedora repositories, after which Node 26 started and reported v26.12.0:

sudo dnf install libatomic

NodeSource’s Node 26 RPM declares that library as a dependency, so dnf installs it for you on that path, and the error only shows up with fnm or another tarball-based manager.

Install the newest Node.js from NodeSource

NodeSource is the option when a server needs the newest point release through dnf, for example to close a security advisory before Fedora rebuilds its package. Its setup script writes a generic “nodistro” RPM repository, so it doesn’t wait for a Fedora-specific tree and worked on Fedora 45 as it stands. Treat it as an alternative to the Fedora packages, not an addition. On a machine that still has nodejs24-bin installed, the install fails at the RPM transaction:

Transaction failed: Rpm transaction failed.
  - file /usr/bin/npm from install of nodejs-2:24.22.0-1nodesource.x86_64 conflicts with file from package nodejs24-npm-bin-2:11.16.0-1.24.18.0.4.fc45.noarch
  - file /usr/bin/npx from install of nodejs-2:24.22.0-1nodesource.x86_64 conflicts with file from package nodejs24-npm-bin-2:11.16.0-1.24.18.0.4.fc45.noarch
  - file /usr/bin/node from install of nodejs-2:24.22.0-1nodesource.x86_64 conflicts with file from package nodejs24-bin-1:24.18.0-4.fc45.noarch
  - file /usr/share/man/man1/node.1.gz from install of nodejs-2:24.22.0-1nodesource.x86_64 conflicts with file from package nodejs24-bin-1:24.18.0-4.fc45.noarch

So remove the Fedora Node packages first. That takes every installed line with it, plus anything that depends on them, such as the pnpm package (19 packages and 542 MiB on our VM). Then download the setup script and run it as a separate step, so you can read what it does before it touches your repositories. For Node 26, fetch setup_26.x instead; we tested the 24 script:

sudo dnf remove "nodejs2*" nodejs nodejs-npm
curl -fsSL https://rpm.nodesource.com/setup_24.x -o /tmp/ns.sh
sudo bash /tmp/ns.sh
sudo dnf install nodejs

The NodeSource package is a single nodejs RPM (133.5 MiB installed) with npm bundled, and dnf asks you to trust the NodeSource signing key (fingerprint 242B813831AF09562B6C46F76B88DA4E3AF28A14) on the first install. Check node --version, npm --version and rpm -q nodejs, which reported the newer releases:

v24.22.0
11.19.1
nodejs-24.22.0-1nodesource.x86_64

Two details in /etc/yum.repos.d/nodesource-nodejs.repo decide how it behaves. The repository sets priority=9, and its packages carry epoch 2 against Fedora’s epoch 1, so dnf will always prefer NodeSource’s nodejs from now on, including during dnf upgrade. That is what you want on a box that follows NodeSource, and a surprise on one that doesn’t. There is no node-24 on such a machine either, so a systemd unit uses plain /usr/bin/node. To back out, remove the package and the repository files, then clear the cached metadata:

sudo dnf remove nodejs
sudo rm -f /etc/yum.repos.d/nodesource-nodejs.repo /etc/yum.repos.d/nodesource-nsolid.repo
sudo dnf clean all

Test Node.js with an Express app

A small Express app proves that npm can reach the registry and that the runtime handles ES modules, and it gives the firewall step something to point at. Any editor works for the one file it needs; if you want an IDE, VS Code on Fedora is the usual pick. Create the project and pull in Express:

mkdir -p ~/hello-api && cd ~/hello-api
npm init -y
npm pkg set type=module
npm install express

Then open the entry point in your editor. The vim command comes from the vim-enhanced package, so install that first if your machine only has vi, or use nano, which is Fedora’s default editor.

vim ~/hello-api/server.js

Add a single route that reports the Node version and process ID. That makes it obvious later which runtime a service is really using, which matters once systemd starts it for you:

import express from 'express';

const app = express();
const port = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.json({ node: process.version, pid: process.pid });
});

app.listen(port, '0.0.0.0', () => {
  console.log(`hello-api listening on port ${port}`);
});

Start it with node server.js and query it from a second terminal with curl -s localhost:3000. You should get JSON back with whichever node comes first in your PATH. A Fedora-only setup shows the packaged 24.18.0 below, while anyone who set up fnm or NodeSource sees their newer build:

{"node":"v24.18.0","pid":7474}

Whether other machines can reach port 3000 depends on the Fedora edition, because each one starts from a different firewall default:

  • Workstation: zone FedoraWorkstation, ports 1025-65535 already open
  • Server: zone FedoraServer, only cockpit, ssh and dhcpv6-client
  • Cloud images: no firewalld installed at all

So a Workstation needs nothing, and a Server needs the port opened by hand. A cloud VM without firewalld isn’t filtering anything on the host, so the provider’s security group or cloud firewall is what decides whether port 3000 is reachable. If you want host filtering there too, install firewalld with sudo dnf install firewalld and add ports before you start it, with sudo firewall-offline-cmd --add-port=3000/tcp. Its default public zone allows SSH only on port 22, so add your SSH port the same way if you moved it, or sudo systemctl enable --now firewalld locks you out. On our cloud VM the offline rule was active as soon as firewalld started. On a Server, where firewalld already runs, add the app port permanently and reload. The firewalld guide for Fedora covers zones and rich rules if you need to limit who can connect:

sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports

The last command should list 3000/tcp. For anything public, put Nginx or another reverse proxy in front with TLS rather than exposing the Node port directly.

Run the Node.js app as a systemd service

A node server.js in a terminal dies with your SSH session, so a real deployment runs under systemd with its own unprivileged user. Create a system account with no login shell, then copy the project to /opt and hand it over:

sudo useradd --system --home-dir /opt/hello-api --shell /sbin/nologin nodeapp
sudo cp -r ~/hello-api /opt/
sudo chown -R nodeapp:nodeapp /opt/hello-api

Create the unit file. The editor opens an empty buffer because nothing on Fedora ships a unit by this name.

sudo vim /etc/systemd/system/hello-api.service

The one line worth thinking about is ExecStart. It calls /usr/bin/node-24 rather than /usr/bin/node, so the service keeps its runtime when someone moves the system default to another line. On a NodeSource machine there is no node-24, so use /usr/bin/node there:

[Unit]
Description=hello-api Node.js service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=nodeapp
WorkingDirectory=/opt/hello-api
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/node-24 server.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

Load the unit, start it and enable it at boot. Run the status check right after, because a typo in the unit only shows up there.

sudo systemctl daemon-reload
sudo systemctl enable --now hello-api
systemctl status hello-api --no-pager

A healthy service shows active (running), about 22 MB of memory for this app, and the same JSON over curl:

Node.js Express app running as a systemd service on Fedora 45 with port 3000 open

We checked the pin the hard way. With the service running on node-24, we moved the system default to Node 26 with --allowerasing and restarted the unit, and the app still answered "node":"v24.18.0". Had the unit called /usr/bin/node, that restart would have quietly put production on a different major version. SELinux stayed enforcing throughout and ausearch -m avc -ts recent returned no denials, because the unit runs a packaged binary against files under /opt. If your app is a container rather than a plain process, Podman Quadlet gives you the same systemd lifecycle, and the rest of a fresh workstation setup is in our Fedora 45 post-install checklist.

Keep reading

How to Upgrade Fedora 44 to Fedora 45 (GUI, CLI and Rollback) Fedora How to Upgrade Fedora 44 to Fedora 45 (GUI, CLI and Rollback) Enable RPM Fusion and Install Multimedia Codecs on Fedora 45 / 44 / 43 Fedora Enable RPM Fusion and Install Multimedia Codecs on Fedora 45 / 44 / 43 Harden Fedora 45 / 44 for Desktop and Server: Complete Guide Fedora Harden Fedora 45 / 44 for Desktop and Server: Complete Guide Switch Fedora From GRUB to systemd-boot With bootctl Fedora Switch Fedora From GRUB to systemd-boot With bootctl DNF5 Cheatsheet for Fedora 45 / 44: Tested Commands and Fixes Fedora DNF5 Cheatsheet for Fedora 45 / 44: Tested Commands and Fixes Install Asterisk 20 LTS on CentOS 7 / RHEL 7 / Fedora Asterisk Install Asterisk 20 LTS on CentOS 7 / RHEL 7 / Fedora

2 thoughts on “Install Node.js and npm on Fedora 45 / 44: Pick 22, 24 or 26”

Leave a Comment

Press ESC to close