Community-driven coverage of elementary OS — news, guides & forums
Dark abstract low-poly geometric landscape with layered triangular facets in deep navy, charcoal, and muted teal, illuminated by a soft electric-blue glow near the horizon

News roundups, tutorials, application guides, and forums — built by users, for users of the elegant Linux distribution.

elementary weekly
#20
Latest roundup · 18 Apr 2015
Freya Release
Final
Covered in weekly #19 & #20
Forum Topics
Active
Installation, customization & more

Setting up a Node.js development environment on elementary OS

A reliable Node.js development environment on elementary OS depends on several tools agreeing: the runtime version, the package manager and the dependencies inside your project. elementary OS 8 is based on Ubuntu 24.04 LTS, providing a modern apt package ecosystem beneath the elementary desktop, with familiar Terminal, Files and application menus.

Developers in Sydney, Melbourne and Brisbane often move between community meetups, open-source repositories and commercial projects with different runtime requirements. Installing one system-wide version and changing it whenever a project needs something else creates unnecessary friction. A version manager lets each project stay on a known release without rebuilding the operating system.

A dependable setup starts with system updates and finishes with an editor and Git working from the same folder. These steps keep Node.js, npm and project dependencies under deliberate control while preserving the elementary OS experience.

Preparing elementary OS for development

Before installing anything, update the package metadata and apply outstanding updates. Run the following in a Terminal window opened from the Applications menu:

sudo apt update
sudo apt upgrade
sudo apt install -y build-essential curl ca-certificates gnupg python3

Reboot if the update process requests it. The compiler tools and Python interpreter can be useful later when npm packages contain native components. Most everyday JavaScript packages need none of them, but installing them now avoids a failed build halfway through a project.

Use your normal administrator account with sudo rather than working as root. Check the active shell with echo "$SHELL" and confirm that it is Bash on a standard installation. The commands here rely on Bash for the small amount of shell configuration used by nvm.

Australian project teams also need an unambiguous time reference. Australia Eastern Standard Time is UTC+10; Sydney and Melbourne move to UTC+11 during daylight saving, while Perth remains on UTC+8. Store timestamps in UTC where possible and convert them for local displays or release schedules.

Installing Node.js through the package repository

The Node.js version available through elementary OS’s own package repositories can be older than a current long-term-support release. NodeSource supplies apt repositories for maintained Node.js releases and integrates with normal system updates.

curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
  | sudo gpg --dearmor -o /usr/share/keyrings/nodesource-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_22.x nodistro main" \
  | sudo tee /etc/apt/sources.list.d/nodesource.list

sudo apt update
sudo apt install -y nodejs

After installation, confirm both the runtime and npm:

node --version
npm --version

NodeSource’s Node 22 branch is a maintained LTS choice. It stays within the 22 release line while receiving patch updates through apt. The exact patch version can change as security fixes arrive, so record the runtime version used by production in your deployment configuration.

Check which executable is active with command -v node and command -v npm. A repository installation normally points to /usr/bin/node, while nvm uses a path inside the current user’s home directory. This distinction matters when a script run through sudo selects a different runtime from your interactive terminal.

The repository-installed nodejs package suits services that should run as a system user. Keep global packages separate from application dependencies, and do not use sudo with npm install --global. A global package can otherwise have a different lifecycle from the Node.js runtime under which it was installed.

Managing Node.js versions with nvm

nvm, the Node Version Manager, installs releases under your home directory and lets you switch between them. It is useful when several projects need different Node.js versions, or when you want to test an application against another release before upgrading it. It is optional if one system-wide LTS release is enough.

Use the official installer, then load the shell changes:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc

Select the current LTS release, make it the default and inspect the installed versions:

nvm install --lts
nvm use --lts
nvm alias default 'lts/*'
nvm ls

Create a .nvmrc file containing an exact version when a project must be reproducible. Team members can run nvm install to fetch that version and nvm use to select it. A deployment system can read the same file when constructing its build environment.

The apt-installed and nvm-managed releases can coexist, but only one is normally first on the shell’s PATH. nvm is a per-user tool: never run its installer or commands with sudo. If a system service explicitly depends on the apt package, leave that package in place and manage user projects through nvm.

Keep the distinction between convenience and reproducibility clear. The lts/* alias follows the newest LTS release when it is installed again, whereas an exact .nvmrc version identifies one immutable runtime. Shared applications and continuous integration jobs benefit from the stricter approach.

Installing Git and Visual Studio Code

Git is the shared history behind most JavaScript projects. Install it from the Ubuntu repositories that elementary OS uses, then set the identity attached to your commits:

sudo apt install -y git
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main

These values apply to every local repository. Use the email address associated with your GitHub, GitLab or Bitbucket account if you want public commits to link to that profile. The global configuration records the author; it does not upload anything by itself.

Visual Studio Code provides a capable editor without requiring a separate IDE installation. The simplest graphical route is to download the Linux .deb package from Microsoft’s official download page and open it with Software Install. For a repeatable terminal installation, add Microsoft’s signed apt repository:

wget -qO- https://packages.microsoft.com/keys/microsoft.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/microsoft-vscode.gpg

echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/microsoft-vscode.gpg] https://packages.microsoft.com/repos/code stable main" \
  | sudo tee /etc/apt/sources.list.d/vscode.list

sudo apt update
sudo apt install -y code

Launch the editor with code ., or choose Visual Studio Code from the Applications menu. Its built-in JavaScript support handles modern ECMAScript. ESLint and other extensions are optional additions once a project has a matching configuration.

For consistent behaviour across workstations, commit .vscode/settings.json and .vscode/extensions.json to the repository. The extensions file records recommended tools without forcing them on every contributor, while shared settings can standardise the formatter and editor rules.

Creating and running a first project

Create a dedicated folder so experiments do not mix with system files, then initialise npm and add a development tool:

mkdir -p ~/Projects/hello-node
cd ~/Projects/hello-node
npm init -y
npm install --save-dev nodemon

npm init creates package.json, the manifest that records scripts and dependencies. The nodemon package restarts the server when a source file changes.

A small server using Node’s built-in HTTP module is enough to verify the complete setup:

cat > server.js <<'EOF'
const http = require('node:http');

const server = http.createServer((request, response) => {
  response.writeHead(200, { 'Content-Type': 'text/plain' });
  response.end('Hello from elementary OS\n');
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000');
});
EOF

Define the start and development scripts, then run the server:

npm pkg set scripts.start="node server.js"
npm pkg set scripts.dev="nodemon server.js"
npm start

Open http://127.0.0.1:3000 in the browser and stop the process with Ctrl+C. A successful response confirms that Node.js, the project directory and the network listener are working. The binding to 127.0.0.1 keeps this test server available only on the machine itself.

For services aimed at Australian customers, remember the surrounding commercial details: a .com.au domain, hosting invoices in Australian dollars and 10% GST on eligible purchases can affect deployment choices. These belong in the service and accounting plan, not in package.json.

Connecting the editor, Git, and npm

Open the project itself, not an unrelated folder, so Visual Studio Code can find .nvmrc, package.json and the terminal’s working directory.

code .

If nvm was installed after the editor was already open, start a new integrated terminal or reload the window. Use the Command Palette to choose a Node.js interpreter when several runtimes are available. An inherited terminal environment can otherwise retain an older PATH.

The npm Scripts view in the Explorer panel exposes scripts from package.json. Running npm run dev there uses the same node_modules directory as the integrated terminal, so there is no need to install packages twice or rely on a global command.

npm run dev

Initialise Git inside the project, ignore generated files and commit the working baseline:

git init
printf "node_modules/\n.env\n" > .gitignore
git add .
git commit -m "Add initial server"

The .gitignore entry keeps the large node_modules directory out of history. Add .env to the same file when the project stores credentials, and supply those variables through your development process or deployment platform instead of committing them.

When a command cannot be found, compare command -v node, echo "$PATH" and command -v npm. Open a fresh terminal after changing .bashrc, and avoid copying absolute nvm paths into project scripts because they belong to one home directory. The editor and shell should agree on the runtime before a confusing dependency error appears.

Comparing Node.js management approaches

Node.js tooling has no single mandatory package manager. The main choices differ in scope: a system repository, a per-user version manager or a tool that pins both the runtime and package managers for each project.

Approach Runtime versions Package installation Best fit Main trade-off
NodeSource through apt One repository release line at a time System-wide; global installs need care Servers and one consistent LTS release Updates affect the whole system
nvm Several versions per user Per user, with per-project selection Teams supporting multiple applications Requires version discipline and shell setup
Volta Several versions per user Tools pinned alongside each project Cross-project toolchain consistency Adds another manager to learn

For a workstation running one Node.js release, the NodeSource repository is the simplest option. For a developer juggling current and older applications, nvm provides explicit version control without changing the machine-wide runtime. Volta suits teams wanting a per-project toolchain, but it introduces another manager rather than filling an obvious gap.

Connection speed can shape the experience of this toolchain. An Australian NBN plan may offer fast downloads while providing modest uploads, and regional users may rely on fixed-line or satellite services instead. Large npm installs, container image pulls and remote Git operations behave differently on a constrained uplink. Check the upload allowance and any data limits before starting a bandwidth-heavy build at home.

Continuous integration should consume the same version information as the workstation. A hosted CI service can install the exact release recorded in .nvmrc, while npm ci honours the committed lockfile. This keeps local development and automated builds aligned without depending on whichever LTS release happens to be newest.

After installation, record the chosen Node.js version in .nvmrc, commit package-lock.json with the application and keep secrets out of Git. The version file, manifest and lockfile together give collaborators and deployment systems the same starting point.

The environment to remember is a deliberate one: a supported runtime, a known version for each project, dependencies installed locally, clean Git history and an editor opened at the project root. Those habits matter more than any particular installation command.

Browse the News Archive
Latest Updates

From the elementary weekly series

Low-poly faceted abstract render in dark charcoal and electric blue tones, suggesting a news bulletin or announcement
elementary news

elementary weekly #20

The first week with the final Freya release — community reactions, tips, and early impressions gathered in one roundup.

Abstract low-poly geometric scene in midnight blue and soft cyan, conveying a live broadcast or event atmosphere
elementary news

elementary SPECIAL

A live Hangouts event with the elementary OS founders, held on 11 April 2015, discussing the Freya final release.

Low-poly faceted render in deep navy and muted teal with subtle amber highlights, suggesting a tutorial or guide
Tips and Tricks

Timeshift Guide

How to use Timeshift — the intuitive system restore utility for elementary OS — to recover from configuration mishaps.

Explore

Topics & Resources

Dive into guides, application recommendations, and community discussions covering every aspect of elementary OS.