Node.js Basics
10 examples to get you started with Node.js Fundamentals - 7 basic and 3 intermediate.
Search across all documentation pages
10 examples to get you started with Node.js Fundamentals - 7 basic and 3 intermediate.
node --version and npm --version (npm 10+ ships with Node 24)."type": "module" in package.json for ESM by default.Confirm the runtime before running any script or deploying.
console.log(process.version); // v24.18.0
console.log(process.versions.v8); // V8 engine version
console.log(process.versions.uv); // libuv versionprocess.version is the authoritative runtime string - log it at startup in production.process.versions exposes V8, libuv, OpenSSL, and other native bindings.package.json engines.Related: Installing & Version Management - pin LTS across teams | Node.js Release & LTS Policy - what production may run
nodeThe simplest way to execute a TypeScript-compiled or plain JavaScript file.
// hello.mjs
console.log('Hello from Node.js', process.version);node hello.mjs.mjs or set "type": "module" in package.json for ESM syntax.node file.ts works with tsx in dev; production compiles with tsc first.Related: Running Scripts & Shebang - make scripts executable
fetchNode 18+ ships a global fetch - no node-fetch package required.
const response = await fetch('https://nodejs.org/dist/index.json');
const releases = await response.json() as Array<{ version: string; lts: string | false }>;
const lts = releases.find((r) => r.lts !== false);
console.log('Current LTS tag:', lts?.lts, lts?.version);fetch returns Web-standard Response objects - same API as browsers.response.ok or response.status before parsing the body.response.body as a Web ReadableStream.Related: How Node.js Works - where I/O runs off the main thread
Configuration belongs in the environment, not hard-coded in source.
const port = Number(process.env.PORT ?? 3000);
const nodeEnv = process.env.NODE_ENV ?? 'development';
console.log(`Starting on port ${port} in ${nodeEnv} mode`);process.env is a plain object of string values - coerce types explicitly.?? for defaults; empty string "" is truthy and will not fall through ||.ESM is the forward path - use static import at the top of files.
import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const pkg = await readFile(path.join(__dirname, 'package.json'), 'utf8');
console.log(JSON.parse(pkg).name);node: for clarity and future-proofing.import.meta.url replaces CJS __filename and __dirname.await is allowed in ESM modules at module scope.Related: How Node.js Works - V8 and the module loader
try/catchAsync errors in await expressions propagate like synchronous throws.
async function loadConfig(): Promise<Record<string, string>> {
try {
const res = await fetch(process.env.CONFIG_URL!);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json() as Record<string, string>;
} catch (err) {
console.error('Config load failed:', err);
throw err; // re-throw so the process exits or a supervisor restarts
}
}.catch() or use try/catch.Prototype APIs interactively without creating a file.
node> await fetch('https://httpbin.org/get').then(r => r.json())
> Object.keys(process.versions)
> .exitawait when started with node (no -e flag needed in Node 24)..save filename to persist a session and .load filename to replay it..help list all dot-commands.Related: The REPL & Quick Experiments - deeper REPL workflows
node:http is built in - no framework required for health checks and probes.
import { createServer } from 'node:http';
const server = createServer((req, res) => {
if (req.url === '/health') {
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ status: 'ok', version: process.version }));
return;
}
res.writeHead(404).end();
});
server.listen(3000, () => console.log('Listening on :3000'));createServer callback runs on every request - keep it non-blocking.content-type explicitly; clients assume text/plain otherwise.node:testNode's built-in test runner needs no Jest install for unit tests.
// math.test.ts
import { test, describe } from 'node:test';
import assert from 'node:assert/strict';
function add(a: number, b: number): number {
return a + b;
}
describe('add', () => {
test('sums two numbers', () => {
assert.equal(add(2, 3), 5);
});
});node --import tsx --test math.test.tsnode:test supports describe, hooks, and async tests natively.node:assert/strict for strict equality checks.tsx in dev for TypeScript; compile before CI if you prefer tsc output.Listen for signals so containers and orchestrators can drain work cleanly.
let shuttingDown = false;
function shutdown(signal: string): void {
if (shuttingDown) return;
shuttingDown = true;
console.log(`Received ${signal}, draining...`);
setTimeout(() => process.exit(0), 2000);
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));SIGTERM before killing a pod - you have ~30 seconds to drain.process.exit.Related: How Node.js Works - single-threaded model and signal handling
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 19, 2026