Node.js & npm

Debian Development Machine Setup

Chapter 6 ยท Node.js & npm

Node.js has the same shape of problem as Python in Chapter 5, with a different twist. Debian packages Node, but the packaged version is fixed at release time, and Node moves quickly. So the question for devserver is not just “how do I install Node?” but “which Node, and how do I change my mind later?” This chapter answers both, and finishes with npm, Node's package manager.

What Debian Gives You

Start with the Chapter 3 checks, before installing anything:

dpkg -s nodejs command -v node type -a node apt policy nodejs npm

On a fresh desktop install Node is probably not there. apt policy shows what Debian offers. On Trixie the nodejs package is 20.19.2 (with Debian's security fixes applied), and npm is a separate package, version 9.2.0, with a long list of dependencies. The nodejs package does depend on corepack, a helper that can give you access to other JavaScript package managers.

The packaged version is already past upstream end-of-life
Node's own release schedule lists Node 20 with an end date of 30 April 2026. Debian's package still receives security fixes from the Debian team, so it is not abandoned, but it is a release line that the Node project itself no longer maintains. That is a reasonable version to run a system tool on. It is not a good version to start new projects on, because the libraries you install will expect something newer.

Which Node? The Release Lines

Node publishes a new major version each year, and gives each an LTS (Long Term Support) phase. As of the end of September 2026, the schedule looks like this:

VersionStatus nowMaintenance phase beginsEnd of life
Node 20 (Iron)End of life22 October 202430 April 2026
Node 22 (Jod)Maintenance LTS21 October 202530 April 2027
Node 24 (Krypton)Active LTS20 October 202630 April 2028
Node 26Current (becomes LTS on 28 October 2026)20 October 202730 April 2029

“Active LTS” is the sweet spot for real work: it is stable and still receiving improvements. Node 24 is the one to pick today, and it is only a few weeks from moving to the less active Maintenance phase, which is still fully supported. The Node project's own advice is that production applications should use Active or Maintenance LTS releases. Check nodejs.org before you decide, because these dates come from the project's published schedule and can be adjusted.

Three Ways to Get Node

MethodVersion you getSwitching versionsTrade-off
Debian package (apt install nodejs npm)Fixed: Node 20 on TrixieNot possibleSimple and integrated with apt, but old, and npm drags in a large set of packages.
A third-party apt repository (such as NodeSource)The major version the repository providesOnly by changing the repositoryNewer, still managed by apt, but you trust a third party's key and packages. Linux Package Managers 3 covers adding repositories safely.
nvm (a version manager)Any version you chooseOne command, or automatic per projectLives in your home directory, outside apt. You manage it yourself.

For a development machine, the version manager is the best fit, for the same reason pyenv was the answer in Chapter 5: different projects want different Node versions, and you should be able to switch without touching the system. This chapter uses nvm (Node Version Manager). If you install Node this way, do not also install the Debian nodejs package. Two Nodes on one machine is exactly the confusion Chapter 3 taught you to avoid.

Installing nvm

The nvm project's documentation gives a one-line installer that pipes a downloaded script into bash. As with pyenv, the safer route is to clone the repository at a specific release and add the shell lines yourself, so you know exactly what runs. The current release at the time of writing is v0.40.8; check the project page for a newer one.

git clone https://github.com/nvm-sh/nvm.git ~/.nvm cd ~/.nvm && git checkout v0.40.8

Then add these lines to ~/.bashrc:

export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

Open a new terminal and check it worked. Note that nvm is a shell function, not a program, so the usual which nvm will find nothing. Use command -v:

command -v nvm # prints: nvm nvm --version

Installing and Switching Node Versions

# Install the latest LTS release and make it the default for new terminals nvm install --lts nvm alias default 'lts/*' node --version npm --version type -a node # See what is installed, and which is active nvm ls nvm current # Install another line alongside it, and switch nvm install 22 nvm use 22 node --version

type -a node now shows a path under ~/.nvm/versions/node/. That is Chapter 3's “first copy wins” idea again: nvm puts the chosen version's directory at the front of your PATH. Switching with nvm use changes which directory is first. Each Node version also comes with its own npm.

Choosing a version per project

Put the version a project needs in a file called .nvmrc in the project's root, and commit it. It contains a version such as 24, or lts/*. Then, from inside the project:

echo 24 > .nvmrc nvm use # reads .nvmrc; run 'nvm install' instead if that version is missing
Match the server
Whatever Node version debserver will run should be the version .nvmrc names, so what you test here is what you deploy there. Decide that before you start the project, not after the first surprise.

npm: Projects and Global Tools

npm does two different jobs, and confusing them causes most npm problems. You already know the equivalent split from Python (Chapter 5): libraries for a project, and tools you run.

Project dependencies

mkdir -p ~/projects/node-demo && cd ~/projects/node-demo npm init -y # creates package.json npm install lodash # adds a dependency: node_modules/, package-lock.json npm install -D prettier # adds a development-only dependency npm ls --depth=0 # what is installed npm outdated # what has newer versions
File / folderWhat it isCommit it?
package.jsonYour project's description and its list of dependencies.Yes
package-lock.jsonThe exact version of every package installed, including dependencies of dependencies.Yes
node_modules/The installed packages themselves. Large, and rebuildable.No (add to .gitignore)

This is the same idea as requirements.txt in Chapter 5. The lock file is the record, and node_modules is disposable. To rebuild exactly what the lock file describes, use npm ci (a clean install from the lock file), rather than npm install, which may update versions:

rm -rf node_modules npm ci

Global tools

Use npm install -g for command-line tools you want available everywhere. With nvm this needs no sudo, because the tools install into the current Node version's own folder in your home directory:

npm install -g cowsay npm ls -g --depth=0 command -v cowsay cowsay "hello from devserver"
Global tools belong to one Node version
Each Node version installed by nvm keeps its own global packages. If you switch to another version with nvm use, a tool you installed globally under the first version can seem to vanish. It has not gone; it is simply installed under the other version. You can carry tools across with nvm install --reinstall-packages-from=current NEW-VERSION. For anything a project depends on, list it in that project's package.json instead of relying on a global copy.
Running a tool once
npx runs a package's command without installing it globally: npx cowsay hi. It is a good way to try something once without leaving anything behind.
Be choosy about what you install
npm packages can run scripts when they install, and a typical project pulls in many dependencies you never chose. Prefer well-known, actively maintained packages, look at what a package is before installing it, and keep the lock file in Git so you can see exactly what changed when it changes.

Which Tool for Which Job

You want to…Use
Pick or switch the Node versionnvm, with a .nvmrc per project
Add a library to a projectnpm install NAME (locked in package-lock.json)
Rebuild a project exactlynpm ci
Install a command-line tool for yourselfnpm install -g NAME (or npx for a one-off)
Run something Debian itself depends onThe apt nodejs package (only if you need it)

For the language itself, see the Node.js Fundamentals course. The next chapter does for PHP what these last two did for Python and Node.

Hands-On Exercises

Exercise 1

Before installing anything, run the Chapter 3 checks for Node on devserver. Then, using the release-line table and the Debian package facts, decide which Node version you will install and write a short justification. Say what would change your mind.

๐Ÿ“„ View solution
Exercise 2

Install nvm and the current LTS, and record what type -a node reports. Then install a second Node major version, create two project folders each with its own .nvmrc, and show that nvm use selects the right version in each.

๐Ÿ“„ View solution
Exercise 3

Create an npm project, install lodash, write a small script that uses it, then delete node_modules and restore it with npm ci. Next, install cowsay globally under one Node version, switch versions, and explain what you see and how to fix it.

๐Ÿ“„ View solution

Chapter 6 Quick Reference

  • Debian 13 packages Node 20.19.2; npm (9.2.0) is a separate, dependency-heavy package. Upstream Node 20 reached end of life on 30 April 2026
  • As of September 2026: Node 24 is Active LTS, Node 22 is Maintenance LTS, Node 26 becomes LTS on 28 October 2026 (check nodejs.org)
  • For development, use a version manager (nvm) rather than the Debian package; do not install both
  • Install nvm at a release tag: git clone https://github.com/nvm-sh/nvm.git ~/.nvm then git checkout v0.40.8, and add three lines to ~/.bashrc
  • command -v nvm (it is a function, so which does not work)
  • nvm install --lts, nvm alias default 'lts/*', nvm ls, nvm use VERSION, nvm current
  • A .nvmrc file pins a project's Node version; nvm use reads it
  • Commit package.json and package-lock.json; never commit node_modules
  • npm ci rebuilds exactly from the lock file; npm install may update versions
  • With nvm, npm install -g needs no sudo, but global tools belong to one Node version; npx runs a tool once