Free lesson · Node.js Deep Dive
Setup: Installing Node, the REPL, the First Program
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 20andfnm use 20. Same pattern for any version.fnm lsshows what you have installed;fnm ls-remoteshows 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:
- Open PowerShell as Administrator and run
wsl --install. - Restart your computer.
- Open the Microsoft Store and install Ubuntu 24.04 LTS.
- Launch Ubuntu, set up your user account.
- Install fnm and Node inside the Ubuntu environment, not in Windows.
- 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
.helpcommand that shows all the dot-commands..loadand.saveare 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:
node- start the REPL.node file.js- run a file.node -e "code"- evaluate a string.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 --versionandnpm --versionreturn reasonable numbers. Open the REPL, multiply 7 by 6, exit cleanly.
Exercise: Core (15 minutes). Type out
hello.jsfrom this lesson (don't copy-paste). Run it. Confirm output. Then modify it: add a new line that prints the current date usingnew Date(). Add another that prints how long Node has been running (process.uptime()).
Exercise: Core (20 minutes). Type out
stats.jsfrom this lesson. Run it. Then extend it with three additions:
- Print the number of files in your current directory using
require('fs').readdirSync('.').length.- Print the current date and time.
- 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 20andfnm use 22. Runnode --versionafter each. Then create a.nvmrcfile in a folder with the content20. Then in that folder, runfnm use. fnm auto-detects the file and switches. Many production teams use.nvmrcfiles to pin Node versions for projects; this is how that works.
Exercise: Stretch (60 minutes). Read the Node.js process documentation. Pick five
processproperties 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:
- Why Node.js exists and what specific 2008-era problem it was built to solve.
- The technical bets Ryan Dahl made - non-blocking I/O, V8, JavaScript on the server.
- Where Node fits in 2026 and where it doesn't.
- How to install Node properly and run code three different ways.
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