Module: Nodejs
Nodejs·116·5 MIN READ

116: Node.js Runtime Fundamentals, Versions, REPL, and Node vs Browser

TOPICS COVERED: Node.js Runtime Fundamentals, Versions, REPL, and Node vs Browser

Learning objectives

By the end of this lesson you should be able to:

  • explain what Node.js is and what it is not;
  • describe the relationship between Node.js, V8, libuv, and operating-system APIs;
  • distinguish the Node runtime from the browser runtime;
  • choose an appropriate Node release line for production;
  • run scripts, evaluate snippets, and use the REPL;
  • understand the global environment, globalThis, and Node-specific globals;
  • explain synchronous versus asynchronous I/O at a high level;
  • identify workloads that are a good or poor fit for a single Node process;
  • inspect runtime, platform, architecture, and version information;
  • build a small command-line program without a framework.

Baseline for this course

As of August 2026, Node.js 24 is an LTS release line while Node.js 26 is the Current release line. Production applications should normally choose a supported LTS line unless a project has a deliberate reason to track Current.

This course uses modern Node APIs and ES modules. Examples assume a supported modern Node release rather than legacy Node 12/14-era patterns.

Check:

bash
node --version
npm --version

Inspect release metadata:

bash
node -p "process.version"
node -p "process.versions"
node -p "process.release"

Do not copy a runtime version from a tutorial without checking whether it is still supported.

What Node.js is

Node.js is a JavaScript runtime designed to execute JavaScript outside the browser.

A useful mental model is:

text
your JavaScript
      ↓
V8 JavaScript engine
      ↓
Node.js APIs + C/C++ bindings
      ↓
libuv / operating-system facilities
      ↓
files, sockets, timers, processes, threads

V8 parses, compiles, and executes JavaScript.

Node adds APIs such as:

text
node:fs
node:http
node:path
node:process
node:stream
node:worker_threads

libuv provides important cross-platform asynchronous I/O and event-loop infrastructure.

Node is therefore more than “Chrome JavaScript without a browser.”

Node.js versus a browser

JavaScript language fundamentals are shared, but the host environment is different.

Browser APIs include:

text
document
window
localStorage
navigator
DOM events

Node APIs include:

text
process
Buffer
filesystem access
TCP/HTTP servers
child processes
worker threads

This works in a browser:

js
document.querySelector('#save');

It does not exist in ordinary Node execution.

This works in Node:

js
import { readFile } from 'node:fs/promises';

const text = await readFile('./notes.txt', 'utf8');

It does not represent a browser capability.

Modern Node also implements many web-compatible APIs such as:

text
fetch
URL
AbortController
EventTarget
Web Streams
crypto web APIs

Do not assume that identical names always mean identical deployment constraints. Check Node documentation and browser support separately.

globalThis

Portable JavaScript can reference the global object through:

js
globalThis

Node historically exposes:

js
global

but new general-purpose code should prefer globalThis when a global reference is truly required.

Avoid putting application state on the global object:

js
globalThis.currentUser = ...

That creates hidden coupling and makes testing/concurrency harder.

Running Node code

Script file

js
// hello.js
console.log('Hello from Node');

Run:

bash
node hello.js

Evaluate an expression

bash
node -e "console.log(process.platform)"
bash
node -p "1 + 2"

Read from standard input

bash
echo "hello" | node -e "
process.stdin.setEncoding('utf8');
process.stdin.on('data', chunk => process.stdout.write(chunk.toUpperCase()));
"

Later lessons cover streams and CLI design deeply.

The Node REPL

Run:

bash
node

Then experiment:

js
1 + 2
process.version
await Promise.resolve('ready')

The REPL is useful for:

  • checking a language expression;
  • inspecting built-in APIs;
  • trying a regular expression;
  • testing a path operation;
  • exploring an object.

It is not a replacement for repeatable tests.

Useful REPL concepts include:

text
.history
.editor
.break
.clear
.exit

Exact commands can evolve; use .help in your installed version.

Node's execution process

A Node program runs inside an operating-system process.

Inspect:

js
console.log({
  pid: process.pid,
  ppid: process.ppid,
  platform: process.platform,
  arch: process.arch,
  cwd: process.cwd(),
});

Example:

js
{
  pid: 43120,
  ppid: 1220,
  platform: 'linux',
  arch: 'x64',
  cwd: '/srv/app'
}

The process has:

  • memory;
  • file descriptors;
  • environment variables;
  • signal handling;
  • current working directory;
  • exit status.

These become important for production services.

The main JavaScript thread

Ordinary Node JavaScript executes on one main JavaScript thread.

That does not mean Node can only do one thing at a time.

For many I/O operations:

text
JavaScript starts operation
→ Node/libuv/OS waits for I/O
→ JavaScript can process other callbacks
→ completion is queued
→ callback/promise continuation runs later

This model is excellent for high-concurrency I/O-heavy workloads.

I/O-bound versus CPU-bound work

I/O-bound

Examples:

text
database calls
HTTP requests
file reads
socket waiting

Node can handle many concurrent operations because waiting does not require the JavaScript thread to spin.

CPU-bound

Examples:

text
large image transformations
video encoding
huge cryptographic loops
compression at scale
machine-learning computation
large synchronous parsing

A long synchronous computation blocks the JavaScript thread:

js
const start = Date.now();

while (Date.now() - start < 5000) {
  // blocks the process for ~5 seconds
}

console.log('finally');

During those five seconds, the same JavaScript thread cannot process ordinary request callbacks.

Later you will use worker threads/processes for CPU-bound work.

Synchronous APIs

Node exposes synchronous APIs:

js
import { readFileSync } from 'node:fs';

const data = readFileSync('./config.json', 'utf8');

Synchronous filesystem work may be reasonable during:

  • one-time CLI startup;
  • build scripts;
  • short administrative scripts.

It is dangerous on a hot request path:

js
app.get('/report', (req, res) => {
  const template = readFileSync('./large-template.html');
  ...
});

because every request blocks the main thread during the read.

Do not memorize “sync APIs are always bad.” Understand where blocking occurs.

Node's built-in module namespace

Prefer explicit built-in specifiers:

js
import fs from 'node:fs';
import path from 'node:path';

The node: prefix makes it obvious that the import is a built-in module rather than an npm package.

Later modules use this style consistently.

A first CLI

Create:

js
// task-summary.js
const tasks = [
  { title: 'Review Node', completed: true },
  { title: 'Learn modules', completed: false },
  { title: 'Build API', completed: false },
];

const completed = tasks.filter((task) => task.completed).length;
const open = tasks.length - completed;

console.log(`Total: ${tasks.length}`);
console.log(`Completed: ${completed}`);
console.log(`Open: ${open}`);

Run:

bash
node task-summary.js

This is ordinary JavaScript plus Node's process/runtime.

Inspect runtime memory

js
console.log(process.memoryUsage());

Typical properties include:

text
rss
heapTotal
heapUsed
external
arrayBuffers

Do not treat a single memory snapshot as a leak diagnosis. Later you will compare trends and heap snapshots.

Exit status

Run:

bash
node -e "process.exitCode = 7"
echo $?

On Windows shells the syntax for inspecting the last exit code differs.

Conventions:

text
0   success
non-zero failure / special result

Libraries/CLIs should document meaningful codes.

Prefer:

js
process.exitCode = 1;

when code can finish normal cleanup, rather than calling:

js
process.exit(1);

which can terminate before pending output flushes.

Signal/shutdown design is covered later.

Common misconceptions

“Node is a framework”

No. Express, Fastify, NestJS, and Hono are frameworks/libraries on top of Node.

“Node is single-threaded”

JavaScript normally runs on a main thread, but Node uses OS asynchronous operations, a libuv thread pool for selected work, and can create worker threads/child processes.

“Async means parallel CPU execution”

No. A Promise does not move CPU-heavy JavaScript to another thread.

“Node and browser JavaScript are the same platform”

The language overlaps; host APIs differ.

“The latest Current release is always best for production”

Production often prioritizes supported LTS stability.

Debug lab

Create:

js
console.log('A');

setTimeout(() => {
  console.log('B');
}, 0);

console.log('C');

Predict output before running.

Then add:

js
Promise.resolve().then(() => {
  console.log('promise');
});

Do not fully explain ordering yet; lesson 119 develops the event loop and microtask model.

Exercises

Foundation

  1. Install a supported Node version with a version manager.
  2. Print process.version, process.platform, and process.arch.
  3. Run a script using node.
  4. Evaluate an expression with node -p.
  5. Use the REPL to inspect process.versions.

Intermediate

  1. Build a task-summary CLI that accepts an in-memory array.
  2. Add an invalid state and set a non-zero process.exitCode.
  3. Compare synchronous and asynchronous file reads for a 50 MB file.

Architecture

For each workload, decide whether a single Node process is a natural fit:

  • REST API waiting on PostgreSQL;
  • WebSocket chat;
  • image transcoding;
  • static file hashing CLI;
  • CPU-heavy PDF generation;
  • proxy service calling upstream APIs.

Explain the reasoning.

Mastery checklist

You should be able to explain:

  • runtime versus language;
  • V8 versus Node versus libuv;
  • browser versus Node host APIs;
  • process versus JavaScript thread;
  • I/O-bound versus CPU-bound;
  • why synchronous work can block a server;
  • LTS versus Current;
  • what globalThis, process, and node: imports represent.

Official references