Node.js Quick Reference
Setup, core modules, npm, Express.js, middleware, file system, streams, child processes and debugging.
Setup & Versions (nvm)
# Install nvm (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# List available versions
nvm ls-remote --lts
# Install and use a specific version
nvm install 22 # install latest v22.x LTS
nvm install 20.11.0 # install exact version
nvm use 22 # switch to v22
nvm alias default 22 # set default version
# Check current version
node --version # v22.x.x
npm --version # 10.x.x
# Run a script with a specific version
nvm exec 20 node app.js
# .nvmrc — pin version per project
echo "22" > .nvmrc
nvm use # reads .nvmrc automatically
Use the LTS (Long Term Support) version for production. Even-numbered major releases (18, 20, 22) become LTS. Odd-numbered releases (19, 21, 23) are short-lived current releases.
Core Modules (fs, path, http, os)
path
import path from 'node:path';
path.join('/users', 'alex', 'docs', 'file.txt');
// '/users/alex/docs/file.txt'
path.resolve('src', 'utils', 'helpers.js');
// '/absolute/path/to/src/utils/helpers.js'
path.basename('/home/alex/app.js'); // 'app.js'
path.basename('/home/alex/app.js', '.js'); // 'app'
path.dirname('/home/alex/app.js'); // '/home/alex'
path.extname('server.config.js'); // '.js'
path.parse('/home/alex/app.js');
// { root: '/', dir: '/home/alex', base: 'app.js', ext: '.js', name: 'app' }
path.isAbsolute('/usr/bin'); // true
path.isAbsolute('./src'); // false
// ES module equivalent of __dirname
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
http
import http from 'node:http';
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello from Node.js' }));
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
os
import os from 'node:os';
os.platform(); // 'linux', 'darwin', 'win32'
os.arch(); // 'x64', 'arm64'
os.cpus().length; // number of CPU cores
os.totalmem(); // total memory in bytes
os.freemem(); // free memory in bytes
os.homedir(); // '/home/alex'
os.tmpdir(); // '/tmp'
os.hostname(); // machine hostname
os.uptime(); // system uptime in seconds
os.networkInterfaces(); // network interface details
NPM & Package Management
# Initialize a new project
npm init -y # creates package.json with defaults
# Install dependencies
npm install express # production dependency
npm install -D typescript # dev dependency
npm install -g nodemon # global install
# Shorthand
npm i express # same as npm install
npm i -D vitest # same as npm install -D
# Remove a package
npm uninstall express
npm rm express # shorthand
# Update
npm outdated # check for outdated packages
npm update # update within semver ranges
npx npm-check-updates -u # update package.json to latest
# Scripts (package.json)
# "scripts": {
# "dev": "node --watch src/index.js",
# "build": "tsc",
# "start": "node dist/index.js",
# "test": "vitest",
# "lint": "eslint src/"
# }
npm run dev
npm test # shorthand for npm run test
npm start # shorthand for npm run start
# Lock files
npm ci # clean install from lock file (CI/CD)
# View package info
npm info express versions
npm ls --depth=0 # list installed top-level packages
# Security
npm audit # check for vulnerabilities
npm audit fix # auto-fix vulnerabilities
| Semver Range | Meaning | Example |
|---|---|---|
^1.2.3 | Compatible (minor + patch) | 1.2.3 to <2.0.0 |
~1.2.3 | Patch-level changes | 1.2.3 to <1.3.0 |
1.2.3 | Exact version | Only 1.2.3 |
* | Any version | Latest available |
Express.js Basics
import express from 'express';
const app = express();
// Built-in middleware
app.use(express.json()); // parse JSON bodies
app.use(express.urlencoded({ extended: true })); // parse form data
app.use(express.static('public')); // serve static files
// Routes
app.get('/', (req, res) => {
res.json({ message: 'Hello World' });
});
app.get('/users/:id', (req, res) => {
const { id } = req.params;
res.json({ userId: id });
});
app.post('/users', (req, res) => {
const { name, email } = req.body;
res.status(201).json({ id: Date.now(), name, email });
});
app.put('/users/:id', (req, res) => {
res.json({ updated: true, id: req.params.id });
});
app.delete('/users/:id', (req, res) => {
res.status(204).send();
});
// Query parameters: GET /search?q=node&page=2
app.get('/search', (req, res) => {
const { q, page = 1 } = req.query;
res.json({ query: q, page: Number(page) });
});
// Router — modular route handling
const router = express.Router();
router.get('/', (req, res) => res.json({ items: [] }));
router.post('/', (req, res) => res.status(201).json(req.body));
router.get('/:id', (req, res) => res.json({ id: req.params.id }));
app.use('/api/items', router);
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Middleware Patterns
// Middleware signature: (req, res, next) => void
// Call next() to pass control to the next middleware
// Logging middleware
function logger(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const ms = Date.now() - start;
console.log(`${req.method} ${req.url} ${res.statusCode} — ${ms}ms`);
});
next();
}
app.use(logger);
// Auth middleware
function requireAuth(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Authentication required' });
}
try {
req.user = verifyToken(token);
next();
} catch {
res.status(403).json({ error: 'Invalid token' });
}
}
// Apply to specific routes
app.get('/profile', requireAuth, (req, res) => {
res.json({ user: req.user });
});
// Apply to all routes in a router
router.use(requireAuth);
// CORS middleware
function cors(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');
if (req.method === 'OPTIONS') return res.status(204).send();
next();
}
// Rate limiter (simple in-memory)
function rateLimit({ windowMs = 60000, max = 100 } = {}) {
const hits = new Map();
return (req, res, next) => {
const key = req.ip;
const now = Date.now();
const record = hits.get(key) || { count: 0, start: now };
if (now - record.start > windowMs) {
record.count = 0;
record.start = now;
}
record.count++;
hits.set(key, record);
if (record.count > max) {
return res.status(429).json({ error: 'Too many requests' });
}
next();
};
}
app.use(rateLimit({ windowMs: 60000, max: 100 }));
// Error-handling middleware (4 arguments)
function errorHandler(err, req, res, next) {
console.error(err.stack);
res.status(err.status || 500).json({
error: err.message || 'Internal Server Error'
});
}
app.use(errorHandler); // must be registered last
File System Operations
import fs from 'node:fs/promises';
import { createReadStream, createWriteStream } from 'node:fs';
// Read file
const content = await fs.readFile('data.txt', 'utf-8');
const json = JSON.parse(await fs.readFile('config.json', 'utf-8'));
const buffer = await fs.readFile('image.png'); // returns Buffer
// Write file
await fs.writeFile('output.txt', 'Hello, World!');
await fs.writeFile('data.json', JSON.stringify(data, null, 2));
// Append to file
await fs.appendFile('log.txt', `${new Date().toISOString()} — Event\n`);
// Check if file/directory exists
try {
await fs.access('config.json');
console.log('File exists');
} catch {
console.log('File does not exist');
}
// Directory operations
await fs.mkdir('logs', { recursive: true }); // create (nested) directory
await fs.rm('temp', { recursive: true, force: true }); // remove directory
const entries = await fs.readdir('src'); // list filenames
const detailed = await fs.readdir('src', { withFileTypes: true });
const files = detailed.filter(e => e.isFile());
const dirs = detailed.filter(e => e.isDirectory());
// File info
const stats = await fs.stat('app.js');
stats.size; // bytes
stats.isFile(); // true
stats.isDirectory(); // false
stats.mtime; // last modified time
// Copy, rename, delete
await fs.copyFile('src.txt', 'dest.txt');
await fs.rename('old.txt', 'new.txt');
await fs.unlink('temp.txt'); // delete file
// Watch for changes
const watcher = fs.watch('src', { recursive: true });
for await (const event of watcher) {
console.log(event.eventType, event.filename);
}
Environment Variables
// Access environment variables
const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;
const nodeEnv = process.env.NODE_ENV; // 'development', 'production', 'test'
// Node.js 20.6+ built-in .env file support
// node --env-file=.env src/index.js
// node --env-file=.env --env-file=.env.local src/index.js
// .env file format:
// PORT=3000
// DATABASE_URL=postgres://user:pass@localhost:5432/mydb
// JWT_SECRET=your-secret-key
// NODE_ENV=development
// Conditional logic based on environment
if (process.env.NODE_ENV === 'production') {
app.use(helmet());
app.use(compression());
}
// Required variable check at startup
const required = ['DATABASE_URL', 'JWT_SECRET', 'REDIS_URL'];
for (const key of required) {
if (!process.env[key]) {
console.error(`Missing required env variable: ${key}`);
process.exit(1);
}
}
// Typed config object
const config = {
port: parseInt(process.env.PORT || '3000', 10),
db: {
url: process.env.DATABASE_URL,
poolSize: parseInt(process.env.DB_POOL_SIZE || '10', 10),
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: process.env.JWT_EXPIRES_IN || '7d',
},
isDev: process.env.NODE_ENV !== 'production',
};
Never commit
.env files with real secrets. Add .env to .gitignore and provide a .env.example with placeholder values for documentation.Child Processes
import { exec, execFile, spawn, fork } from 'node:child_process';
import { promisify } from 'node:util';
const execAsync = promisify(exec);
// exec — runs a shell command, buffers output
const { stdout, stderr } = await execAsync('ls -la');
console.log(stdout);
// execFile — runs a file directly (no shell, safer)
const execFileAsync = promisify(execFile);
const { stdout: gitLog } = await execFileAsync('git', ['log', '--oneline', '-5']);
// spawn — streaming output (for long-running processes)
const child = spawn('npm', ['run', 'build']);
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
child.on('close', (code) => {
console.log(`Process exited with code ${code}`);
});
// fork — spawn a new Node.js process with IPC channel
// worker.js
// process.on('message', (msg) => {
// const result = heavyComputation(msg.data);
// process.send({ result });
// });
const worker = fork('./worker.js');
worker.send({ data: largeDataSet });
worker.on('message', (msg) => {
console.log('Result:', msg.result);
});
// Using AbortController to cancel
const controller = new AbortController();
const { signal } = controller;
const child = spawn('long-task', [], { signal });
setTimeout(() => controller.abort(), 10000);
child.on('error', (err) => {
if (err.code === 'ABORT_ERR') console.log('Process aborted');
});
Streams
import { createReadStream, createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream/promises';
import { createGzip, createGunzip } from 'node:zlib';
import { Transform } from 'node:stream';
// Read stream — reads file in chunks (memory efficient)
const readStream = createReadStream('large-file.txt', { encoding: 'utf-8' });
readStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes`);
});
readStream.on('end', () => console.log('Done reading'));
readStream.on('error', (err) => console.error(err));
// Write stream
const writeStream = createWriteStream('output.txt');
writeStream.write('Line 1\n');
writeStream.write('Line 2\n');
writeStream.end('Final line\n');
// Pipe — connect streams
createReadStream('input.txt')
.pipe(createWriteStream('output.txt'));
// Pipeline (preferred) — handles errors and cleanup automatically
await pipeline(
createReadStream('input.txt'),
createGzip(),
createWriteStream('input.txt.gz')
);
// Decompress
await pipeline(
createReadStream('input.txt.gz'),
createGunzip(),
createWriteStream('input-restored.txt')
);
// Custom transform stream
const upperCase = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString().toUpperCase());
}
});
await pipeline(
createReadStream('input.txt'),
upperCase,
createWriteStream('output-upper.txt')
);
// Line-by-line processing with readline
import { createInterface } from 'node:readline';
const rl = createInterface({
input: createReadStream('data.csv'),
crlfDelay: Infinity,
});
for await (const line of rl) {
const [name, email] = line.split(',');
console.log({ name, email });
}
Streams are essential for processing large files without loading them entirely into memory. A 2 GB file can be processed with ~64 KB of memory using streams.
Error Handling & Debugging
// Async error handling — always wrap async operations
async function fetchData(url) {
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return await res.json();
} catch (err) {
if (err.cause) console.error('Caused by:', err.cause);
throw err;
}
}
// Custom error classes
class AppError extends Error {
constructor(message, statusCode = 500, code = 'INTERNAL_ERROR') {
super(message);
this.name = 'AppError';
this.statusCode = statusCode;
this.code = code;
}
}
class NotFoundError extends AppError {
constructor(resource = 'Resource') {
super(`${resource} not found`, 404, 'NOT_FOUND');
}
}
// Uncaught exception and rejection handlers
process.on('uncaughtException', (err) => {
console.error('Uncaught Exception:', err);
process.exit(1); // exit — state may be corrupted
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
// Graceful shutdown
function gracefulShutdown(signal) {
console.log(`${signal} received. Shutting down gracefully...`);
server.close(() => {
console.log('HTTP server closed');
db.disconnect().then(() => process.exit(0));
});
setTimeout(() => process.exit(1), 10000); // force exit after 10s
}
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
// Built-in debugging
// node --inspect src/index.js → Chrome DevTools debugger
// node --inspect-brk src/index.js → break on first line
// node --watch src/index.js → auto-restart on changes (Node 18+)
// Debug logging with NODE_DEBUG
// NODE_DEBUG=http,net node app.js → verbose built-in module logging
// Console timing
console.time('db-query');
const result = await db.query('SELECT * FROM users');
console.timeEnd('db-query'); // db-query: 42.123ms
// Structured logging
console.log(JSON.stringify({
level: 'info',
message: 'Request processed',
method: req.method,
url: req.url,
status: res.statusCode,
duration: ms,
timestamp: new Date().toISOString()
}));