This article provides step-by-step instructions on how to install Node.js via Node Version Manager (NVM) on a personal computer running on Ubuntu 21.04.

Tested environment

An x64-based laptop running on Ubuntu 21.04

  • Linux kernel version: 5.11.0-17-generic

Ubuntu 20.04 subsystem running on Microsoft Windows 10 Home

  • Windows host: 20H2 (OS Build 19042.985)

  • Linux kernel version: 4.4.0-19041-Microsoft

Node.js installation via NVM

Installing NVM using install script

Node Version Manager (aka, NVM) allows you to install and maintain different versions of Node.js and their associated Node packages.

To install the latest NVM package, visit the project’s GitHub page and copy the Curl command from the Installing & Updating section on the main page.

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash (1)
1 The leading symbol $ indicates that you are typing at a Ubuntu Terminal.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 14926  100 14926    0     0  15761      0 --:--:-- --:--:-- --:--:-- 15744
=> Downloading nvm as script to '/home/hawk/.nvm'

=> Appending nvm source string to /home/hawk/.bashrc
=> Appending bash_completion source string to /home/hawk/.bashrc
=> Close and reopen your terminal to start using nvm or run the following to use it now:

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

Running the above curl command will add the following script to your '.bashrc' file:

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

To update with the added setting, reread your '.bashrc' file using the source command:

$ source ~/.bashrc

Now, check the NVM installation by the version:

$ nvm --version
0.38.0

Installing Node.js using NVM

Let us try to list all available Node.js versions using the nvm ls-remote command:

$ nvm ls-remote | grep -i 'lts'
          :
       v14.15.0   (LTS: Fermium)
       v14.15.1   (LTS: Fermium)
       v14.15.2   (LTS: Fermium)
       v14.15.3   (LTS: Fermium)
       v14.15.4   (LTS: Fermium)
       v14.15.5   (LTS: Fermium)
       v14.16.0   (LTS: Fermium)
       v14.16.1   (LTS: Fermium)
       v14.17.0   (Latest LTS: Fermium)

You may visit nodejs.org to find out the latest LTS (Long Time Support) release number.

  • The current release used in this article: v14.17.0

On deciding which version to install, open a Terminal and get the Node.js release using nvm install:

$ nvm install v14.17.0
Downloading and installing node v14.17.0...
Downloading https://nodejs.org/dist/v14.17.0/node-v14.17.0-linux-x64.tar.xz...
#################################################################################################################### 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v14.17.0 (npm v6.14.13)
Creating default alias: default -> v14.17.0

Node and NPM versions

You can check the Node.js installation by the version:

$ node --version
v14.17.0

Also, check the version of NPM, the Node.js Package Manager:

$ npm --version
6.14.13

You can check your global 'node_modules' location by entering:

$ npm root -g
/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules

To list globally installed packages to the first level, enter:

$ npm list -g --depth 1
/home/hawk/.nvm/versions/node/v14.17.0/lib
└─┬ npm@6.14.13
  ├── abbrev@1.1.1
  ├── ansicolors@0.3.2
  ├── ansistyles@0.1.3
  ├── aproba@2.0.0
  ├── archy@1.0.0
  ├── bin-links@1.1.8
  ├── bluebird@3.5.5
  ├── byte-size@5.0.1
  ├── cacache@12.0.3
  ├── call-limit@1.1.1
  ├── chownr@1.1.4
  ├── ci-info@2.0.0
  ├── cli-columns@3.1.2
  ├── cli-table3@0.5.1
  ├── cmd-shim@3.0.3
  ├── columnify@1.5.4
  ├── config-chain@1.1.12
  ├── debuglog@1.0.1
  ├── detect-indent@5.0.0
  ├── detect-newline@2.1.0
  ├── dezalgo@1.0.3
  ├── editor@1.0.0
  ├── figgy-pudding@3.5.1
  ├── find-npm-prefix@1.0.2
  ├── fs-vacuum@1.2.10
  ├── fs-write-stream-atomic@1.0.10
  ├── gentle-fs@2.3.1
  ├── glob@7.1.6
  ├── graceful-fs@4.2.4
  ├── has-unicode@2.0.1
  ├── hosted-git-info@2.8.9
  ├── iferr@1.0.2
  ├── imurmurhash@0.1.4
  ├── infer-owner@1.0.4
  ├── inflight@1.0.6
  ├── inherits@2.0.4
  ├── ini@1.3.8
  ├── init-package-json@1.10.3
  ├── is-cidr@3.0.0
  ├── json-parse-better-errors@1.0.2
  ├── JSONStream@1.3.5
  ├── lazy-property@1.0.0
  ├── libcipm@4.0.8
  ├── libnpm@3.0.1
  ├── libnpmaccess@3.0.2
  ├── libnpmhook@5.0.3
  ├── libnpmorg@1.0.1
  ├── libnpmsearch@2.0.2
  ├── libnpmteam@1.0.2
  ├── libnpx@10.2.4
  ├── lock-verify@2.1.0
  ├── lockfile@1.0.4
  ├── lodash._baseindexof@3.1.0
  ├── lodash._baseuniq@4.6.0
  ├── lodash._bindcallback@3.0.1
  ├── lodash._cacheindexof@3.0.2
  ├── lodash._createcache@3.1.2
  ├── lodash._getnative@3.9.1
  ├── lodash.clonedeep@4.5.0
  ├── lodash.restparam@3.6.1
  ├── lodash.union@4.6.0
  ├── lodash.uniq@4.5.0
  ├── lodash.without@4.4.0
  ├── lru-cache@5.1.1
  ├── meant@1.0.2
  ├── mississippi@3.0.0
  ├── mkdirp@0.5.5
  ├── move-concurrently@1.0.1
  ├── node-gyp@5.1.0
  ├── nopt@4.0.3
  ├── normalize-package-data@2.5.0
  ├── npm-audit-report@1.3.3
  ├── npm-cache-filename@1.0.2
  ├── npm-install-checks@3.0.2
  ├── npm-lifecycle@3.1.5
  ├── npm-package-arg@6.1.1
  ├── npm-packlist@1.4.8
  ├── npm-pick-manifest@3.0.2
  ├── npm-profile@4.0.4
  ├── npm-registry-fetch@4.0.7
  ├── npm-user-validate@1.0.1
  ├── npmlog@4.1.2
  ├── once@1.4.0
  ├── opener@1.5.2
  ├── osenv@0.1.5
  ├── pacote@9.5.12
  ├── path-is-inside@1.0.2
  ├── promise-inflight@1.0.1
  ├── qrcode-terminal@0.12.0
  ├── query-string@6.8.2
  ├── qw@1.0.1
  ├── read@1.0.7
  ├── read-cmd-shim@1.0.5
  ├── read-installed@4.0.3
  ├── read-package-json@2.1.1
  ├── read-package-tree@5.3.1
  ├── readable-stream@3.6.0
  ├── readdir-scoped-modules@1.1.0
  ├── request@2.88.0
  ├── retry@0.12.0
  ├── rimraf@2.7.1
  ├── safe-buffer@5.1.2
  ├── semver@5.7.1
  ├── sha@3.0.0
  ├── slide@1.1.6
  ├── sorted-object@2.0.1
  ├── sorted-union-stream@2.1.3
  ├── ssri@6.0.2
  ├── stringify-package@1.0.1
  ├── tar@4.4.13
  ├── text-table@0.2.0
  ├── tiny-relative-date@1.3.0
  ├── uid-number@0.0.6
  ├── umask@1.1.0
  ├── unique-filename@1.1.1
  ├── unpipe@1.0.0
  ├── update-notifier@2.5.0
  ├── uuid@3.3.3
  ├── validate-npm-package-license@3.0.4
  ├── validate-npm-package-name@3.0.0
  ├── which@1.3.1
  ├── worker-farm@1.7.0
  └── write-file-atomic@2.4.3

Updating NPM via NVM

To update NPM to the latest version, you may enter:

$ nvm install-latest-npm
Attempting to upgrade to the latest working version of npm...
* Installing latest `npm`; if this does not work on your node version, please report a bug!
/home/hawk/.nvm/versions/node/v14.17.0/bin/npm -> /home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/npm/bin/npm-cli.js
/home/hawk/.nvm/versions/node/v14.17.0/bin/npx -> /home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/npm/bin/npx-cli.js
+ npm@7.13.0
added 60 packages from 23 contributors, removed 241 packages and updated 194 packages in 4.284s
* npm upgraded to: v7.13.0

NPM update failure on Ubuntu 20.04 WSL

Unfortunately, the above nvm install-latest-npm command fails on Ubuntu 20.04 subsystem:

Attempting to upgrade to the latest working version of npm...
* Installing latest `npm`; if this does not work on your node version, please report a bug!
npm ERR! code EACCES
npm ERR! syscall rename
npm ERR! path /home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/npm-237224bb/node_modules/string-width
npm ERR! dest /home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/string-width-e64662c3
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, rename '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/npm-237224bb/node_modules/string-width' -> '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/string-width-e64662c3'
npm ERR!  [OperationalError: EACCES: permission denied, rename '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/npm-237224bb/node_modules/string-width' -> '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/string-width-e64662c3'] {
npm ERR!   cause: [Error: EACCES: permission denied, rename '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/npm-237224bb/node_modules/string-width' -> '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/string-width-e64662c3'] {
npm ERR!     errno: -13,
npm ERR!     code: 'EACCES',
npm ERR!     syscall: 'rename',
npm ERR!     path: '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/npm-237224bb/node_modules/string-width',
npm ERR!     dest: '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/string-width-e64662c3'
npm ERR!   },
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'rename',
npm ERR!   path: '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/npm-237224bb/node_modules/string-width',
npm ERR!   dest: '/home/hawk/.nvm/versions/node/v14.17.0/lib/node_modules/.staging/string-width-e64662c3'
npm ERR! }
npm ERR!
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/hawk/.npm/_logs/2021-05-16T05_28_32_465Z-debug.log
* npm upgraded to: v6.14.13

Let us stick to the current version of NPM, until the issue is resolved.

NPM 101

Local installation vs global installation

When you install a Node application using NPM, you may do it either locally or globally. Local packages are installed where you are running the npm install command. Local packages will be placed under the 'node_modules' directory in the local location. Global packages, in comparison, are all put in a single place in your system (the exact location depends on your setup) regardless of where you run the npm install command.

If you are going to include the package using a statement like require('package-name') in your '.js' implementation, it suffices you to install it locally. Use the command

npm install <package-name>

If you plan to use the package as a command-line tool, ie, to be available from any folder location, you need to perform a global installation.

npm install -g <package-name>

Which one shall I use?

The developers suggest all packages should be installed locally, even if this might seem a waste of storage space. The reasons are:

  • This allows you to have dozens of applications on your computer, all running different versions of each package as required.

  • It is much safer compared to the possible negative consequences in cases globally updating packages might go mad.

  • Note you can also install executable commands locally and run them using npx.

That said, a globally installed package enables you to run the executable from any folder location and also becomes reusable across projects. There exist popular global packages such as npm, create-react-app, vue-cli, grunt-cli, etc.

Installing a specific version of a package

To install a specific version of a Node package, use the command syntax:

npm install <package-name>@<version>

To install a package referenced by a specified tag (eg, something like the latest tag in the npm@latest argument), enter:

npm install <package-name>@<tag>

Uninstalling a Node package

To uninstall a locally installed package, use the following command from your project root folder, ie, the folder that contains the 'node_modules' directory:

npm uninstall <package-name>

If the package is installed globally, use the command syntax:

npm uninstall -g <package-name>

'Hello, World!' using Node.js

In this section, we will test our installation of Node.js using a simple web application.

Using any text editor (eg, Gedit or SciTE, etc), enter — or cut-and-paste — the below content and save it as "helloWorld.js" to a local work folder.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const http = require('http')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('Hello, World!\n')
})

server.listen(port, hostname, () => {
  console.log(Server running at http://${hostname}:${port}/)
})

Open a Terminal and run the script using node

$ node ./helloWorld.js

which should print out a message similar to the following:

Server running at http://127.0.0.1:3000/

To see the processed output, enter the below command in a browser address bar:

localhost:3000
shot0101

To shut down the server, press Ctrl+C from inside the Terminal. Also, close the browser tab accordingly.