AlgoInsight

Free lesson · Node.js Deep Dive

Setup: Installing Node, the REPL, the First Program

Easy11 min readnodejsjavascriptbackend

Setup: Installing Node, the REPL, the First Program

This is the practical lesson. By the end of it, you'll have Node installed properly on your machine, you'll know how to run JavaScript code in three different ways, and you'll have written your first program.

I'm going to be opinionated about how you install Node. There's a popular wrong way that the official Node website nudges you toward, and there's a better way that almost every working Node developer uses. We're going with the better way.


Don't Use the Installer From nodejs.org

If you go to nodejs.org and click the big green download button, it gives you a system-wide installer that puts Node into /usr/local/bin/node (on macOS and Linux) or C:\Program Files\nodejs\ (on Windows). This works for a "let me try Node tonight" use case. It is the wrong approach for any actual development work.

The problem: real projects pin to specific Node versions. You'll work on a project that requires Node 18, then switch to one that requires Node 20, then a side project on Node 22. The system-wide installer can only have one Node at a time. Upgrading or switching is painful and sometimes breaks the previous project.

The right approach: use a version manager. A version manager lets you install many Node versions side-by-side and switch between them per-project. This is how every Node developer I work with manages their environment. There are three good options.


Pick a Version Manager

nvm - Node Version Manager. The original. Bash/zsh script-based, macOS and Linux only (there's a separate nvm-windows project that's similar but not the same codebase). I used nvm for years. Most older tutorials assume nvm. It's solid.

fnm - Fast Node Manager. A modern alternative written in Rust. Faster than nvm at every operation. Cross-platform - works on macOS, Linux, and Windows natively. This is what I currently use. If you're starting fresh in 2026, I'd recommend fnm.

Volta. Another Rust-based version manager, with a focus on per-project version pinning being automatic. Also cross-platform. Some teams prefer it. Slightly different mental model from nvm/fnm.

My recommendation: install fnm. The differences between these tools are minor; they all let you install and switch Node versions. fnm is fast, modern, cross-platform, and the default many new projects assume now.

Installing fnm

macOS and Linux:

# Install fnm using the official install script
curl -fsSL https://fnm.vercel.app/install | bash

# Restart your shell, or source your shell config
source ~/.zshrc  # if you use zsh
source ~/.bashrc # if you use bash

Windows:

# Install via winget (Windows 11 and modern Windows 10)
winget install Schniz.fnm

# Or via Chocolatey if you use it
choco install fnm

After installation, verify fnm is working:

fnm --version

You should see a version number printed. If you see "command not found," fnm didn't end up in your PATH; check the post-install instructions for fnm specific to your OS.

Installing Node via fnm

Now install the current LTS version of Node:

fnm install --lts

This downloads and installs the most recent LTS release. As of writing, that's Node 22.x. Then set it as the default:

fnm use --lts
fnm default $(fnm current)

Verify:

node --version
npm --version

You should see version numbers - v22.x.x for Node and 10.x.x (or similar) for npm. npm comes bundled with Node; you don't install it separately.

Tip: If you want to install a specific Node version (say, because a project requires Node 20), just fnm install 20 and fnm use 20. Same pattern for any version. fnm ls shows what you have installed; fnm ls-remote shows what's available to install.


A Note for Windows Users

If you're on Windows and not using WSL2 (Windows Subsystem for Linux 2), I'd strongly recommend setting up WSL2 before continuing.

Native Windows is not the path most Node developers walk. The Node.js ecosystem is heavily Linux/macOS-oriented. Many tutorials assume bash-style commands. Some npm packages have native dependencies that build cleanly on Linux/macOS but have edge cases on Windows. WSL2 gives you a real Linux environment inside Windows, with file system integration with VS Code, and it makes the entire Node experience smoother.

To set up WSL2:

  1. Open PowerShell as Administrator and run wsl --install.
  2. Restart your computer.
  3. Open the Microsoft Store and install Ubuntu 24.04 LTS.
  4. Launch Ubuntu, set up your user account.
  5. Install fnm and Node inside the Ubuntu environment, not in Windows.
  6. Install VS Code on Windows, plus the Remote - WSL extension. Open your project from inside Ubuntu and VS Code will connect cleanly.

This is what I'd set up for someone joining my team. Native Windows works, but you'll hit more friction.


VS Code Setup

I'm going to be biased here because I work on VS Code at Microsoft, but I genuinely think it's the best Node development environment in 2026 - even if you disregard my bias.

Install VS Code for your operating system if you don't have it already.

Install these extensions:

Extension Why
ESLint Lints your code as you write it. Module 12 covers ESLint in depth.
Prettier - Code formatter Auto-formats your code. Save yourself the holy war and just use Prettier defaults.
DotENV Syntax highlighting for .env files.
GitLens Git superpowers - see who changed a line, when, why.
Error Lens Inline display of errors and warnings. Major productivity boost.
Pretty TypeScript Errors Makes TypeScript errors readable. We'll need this in Module 19.

Configure VS Code to format on save. Open Settings (Cmd+, on macOS, Ctrl+, on Windows/Linux), search for "format on save," and check the box.

Tip: If you want my exact VS Code config - the settings.json, the extensions, the keybindings - I publish them in the AlgoInsight Discord. There's nothing magical there, but it might save you an afternoon of tinkering.


The REPL: Your First Node Interactive Session

Open a terminal and run:

node

You'll see something like this:

Welcome to Node.js v22.x.x.
Type ".help" for more information.
>

This is the Node REPL - Read-Eval-Print Loop. It's an interactive JavaScript environment. Whatever you type gets evaluated immediately.

Try a few things:

> 2 + 2
4
> "hello".toUpperCase()
'HELLO'
> const greet = (name) => `Hello, ${name}!`;
undefined
> greet("Olena")
'Hello, Olena!'
> [1, 2, 3].map(n => n * 2)
[ 2, 4, 6 ]

When you define something (a variable, a function), the REPL prints undefined because the assignment statement itself has no value. That's normal.

You also have access to all of Node's built-in modules:

> const os = require('os');
undefined
> os.platform()
'darwin'        // or 'linux' or 'win32', depending on your machine
> os.cpus().length
8               // or however many CPU cores your machine has
> os.totalmem() / 1024 / 1024 / 1024
16.0            // total RAM in gigabytes

To exit the REPL, type .exit or press Ctrl+D twice.

The REPL is genuinely useful. I use it daily - when I want to test what a regex does, or how a specific Date method behaves, or just to do quick math while I'm coding. It's the JavaScript equivalent of opening a Python interactive shell.

Note: The REPL has a .help command that shows all the dot-commands. .load and .save are particularly useful - they load/save files into the REPL session, so you can experiment with a function defined in a file.


Running JavaScript From a File

The REPL is great for experimentation. For actual programs, you write code in a file and run it with node filename.js.

Create a folder for your course work:

mkdir -p ~/code/nodejs-course
cd ~/code/nodejs-course

Open it in VS Code:

code .

Create a file called hello.js in VS Code with this content:

const greeting = "Hello from Node.js";
const versions = process.versions;

console.log(greeting);
console.log(`Running on Node ${versions.node}`);
console.log(`V8 version: ${versions.v8}`);
console.log(`OpenSSL version: ${versions.openssl}`);

Save it. Then in your terminal:

node hello.js

You should see output like:

Hello from Node.js
Running on Node 22.x.x
V8 version: 12.x.x
OpenSSL version: 3.x.x

A few things are happening here worth pointing out:

process is a built-in global. Every Node program has a process object. It exposes information about the running Node process - versions, environment variables, command-line arguments, working directory, the ability to exit. We'll come back to process in many places throughout the course.

process.versions is a real object. It's not just process.version (the Node version) - process.versions shows you the versions of all the internal pieces. V8 is the JavaScript engine. OpenSSL is the cryptography library. There are usually 10-15 entries in there. Try console.log(process.versions) to see them all. This is concrete evidence of what we discussed in Lesson 1.3: Node is built from V8 plus a bunch of C libraries glued together.

console.log works the way you'd expect. In Node, console.log writes to stdout. In a browser, it writes to the developer tools console. The API is mostly the same but underneath, they're different.


The Three Ways to Run JavaScript in Node

You now know two: the REPL and node filename.js. There's a third worth mentioning: inline evaluation.

node -e "console.log(process.platform)"

The -e flag means "evaluate this string of code." Useful for one-off commands in scripts. I use it constantly in shell scripts when I need to do JavaScript work as part of a larger pipeline.

You can also pipe code into Node:

echo "console.log(2 + 2)" | node

That's all four:

  1. node - start the REPL.
  2. node file.js - run a file.
  3. node -e "code" - evaluate a string.
  4. command | node - pipe code in via stdin.

What's In Your Node Install

Let me show you what fnm actually downloaded. Run:

which node          # macOS/Linux
where.exe node      # Windows

You'll see a path under your user's home directory (something like ~/.local/share/fnm/...), not /usr/local/bin. That's because fnm installs Node into your user space, not system-wide. This is the version-manager pattern: each Node version lives in its own folder, fnm shims them onto your PATH.

If you cd into that folder, you'll see:

node-v22.x.x/
├── bin/
│   ├── node       # the Node binary itself
│   ├── npm        # the npm binary (just a script that runs node + npm-cli.js)
│   └── npx        # the npx binary
├── include/
│   └── node/      # C++ header files for native modules
├── lib/
│   └── node_modules/
│       ├── npm/   # npm itself is implemented in JavaScript
│       └── corepack/
└── share/
    └── doc/

The node binary is about 80-100 MB. That's V8 (~30 MB), libuv, the Node C++ code, the JavaScript standard library, all linked together. You don't need to know the internals of the binary; I'm pointing this out so you understand Node is a single executable that bundles everything we discussed in Lesson 1.3.


Your First Real Program

Let me give you something slightly more interesting than "hello world." Create a file called stats.js:

// stats.js - print some info about the machine and Node process

const os = require('os');
const process_ = process;

console.log('=== Machine ===');
console.log('Platform:', os.platform());
console.log('Architecture:', os.arch());
console.log('CPUs:', os.cpus().length, 'cores');
console.log('Memory:', Math.round(os.totalmem() / 1024 / 1024 / 1024), 'GB');
console.log('Hostname:', os.hostname());
console.log();

console.log('=== Node Process ===');
console.log('Node version:', process_.version);
console.log('V8 version:', process_.versions.v8);
console.log('PID:', process_.pid);
console.log('Working directory:', process_.cwd());
console.log('Uptime:', process_.uptime(), 'seconds');
console.log();

console.log('=== Environment ===');
console.log('User:', process_.env.USER || process_.env.USERNAME);
console.log('Path entries:', process_.env.PATH.split(':').length);
console.log('Node executable:', process_.execPath);

Run it:

node stats.js

Read through the code. You're using require to import the os module - Node's built-in module for operating system info. You're calling functions and printing the results. Nothing fancy, but it's a real program that does something useful.

Now modify it. Add a section that prints the current date and time. Add a section that prints the total free memory. Add a check that warns you if your machine has less than 8 GB of RAM. The point isn't to write a useful program - it's to start touching Node code with your hands. Reading is not the same as typing.


Common Setup Problems and Fixes

If something didn't work, here are the issues I see most often.

"command not found: node" - fnm probably didn't update your shell config. Close and reopen your terminal. If that doesn't help, manually add the fnm init line to your ~/.zshrc or ~/.bashrc. fnm's docs explain the exact line.

Permission errors when running npm globally - you might have installed Node via the official installer in addition to via fnm. Run which node and which npm and verify they're under your home directory. If they're not (/usr/local/bin/node), uninstall the system Node and start over with fnm.

Slow npm installs - could be your network, could be your registry. Run npm config get registry. It should say https://registry.npmjs.org/. If it doesn't, you're probably pointed at a slow mirror.

"This package requires Node X" errors - install the required version with fnm. fnm install 18, fnm use 18. Then go back to your default when done.

Permission errors on Windows - usually a sign you're not in WSL2. Strongly consider WSL2.

If you're still stuck after trying these, post in the AlgoInsight Discord with the exact error message and your OS. Setup issues are common and other students hit the same ones.


What I Want You to Take From This Lesson

Three things.

One: Use a version manager. fnm specifically, but any of the three will do. The official Node installer is a beginner trap.

Two: Get the REPL into your habit. When you wonder "I bet [1,2,3].includes returns a boolean - does it?", don't google. Open the REPL and find out. The REPL is the fastest possible feedback loop.

Three: Set up VS Code well once. Format on save, ESLint, Error Lens. A well-configured editor is a force multiplier. I work in VS Code daily; my setup is the result of small improvements over years.

This concludes Module 1. You now have Node installed, you know its history, you understand its design rationale, and you've placed it in the modern landscape. Module 2 starts the real technical content - a JavaScript refresher focused on the patterns that matter for Node.


Try It

Exercise: Warmup (10 minutes). Install fnm. Install Node LTS via fnm. Verify both node --version and npm --version return reasonable numbers. Open the REPL, multiply 7 by 6, exit cleanly.

Exercise: Core (15 minutes). Type out hello.js from this lesson (don't copy-paste). Run it. Confirm output. Then modify it: add a new line that prints the current date using new Date(). Add another that prints how long Node has been running (process.uptime()).

Exercise: Core (20 minutes). Type out stats.js from this lesson. Run it. Then extend it with three additions:

  1. Print the number of files in your current directory using require('fs').readdirSync('.').length.
  2. Print the current date and time.
  3. Add a warning that prints if os.totalmem() is less than 8 GB.

Exercise: Stretch (45 minutes). Install two different Node versions with fnm - say, Node 20 and Node 22. Switch between them with fnm use 20 and fnm use 22. Run node --version after each. Then create a .nvmrc file in a folder with the content 20. Then in that folder, run fnm use. fnm auto-detects the file and switches. Many production teams use .nvmrc files to pin Node versions for projects; this is how that works.

Exercise: Stretch (60 minutes). Read the Node.js process documentation. Pick five process properties or methods you haven't seen and write a small program that uses each. Examples to consider: process.argv, process.env, process.platform, process.memoryUsage(), process.hrtime.bigint().


Module 1 Complete

Take a moment before moving on. You now know:

If any of these feels shaky, go back. Module 2 assumes Module 1.

When you're ready, Module 2 starts with a JavaScript refresher specifically focused on the patterns that matter for Node - closures in callbacks, async/await under the hood, the modules history, and a few subtle things JavaScript newcomers often get wrong without knowing it.

— Olena

Back to Node.js Deep Dive