Node.js Cheat Sheet
A quick-reference card for Node.js patterns, built-in module APIs, and idiomatic code. Use this as a day-to-day lookup rather than a tutorial — each section links to the deeper page where appropriate.
Process and environment
TS
process.env.NODE_ENV // 'development' | 'production' | 'test'
process.env.PORT ?? '3000' // always a string — coerce explicitly
process.argv // ['node', 'script.js', ...rest]
process.argv.slice(2) // user arguments only
process.cwd() // current working directory
process.exit(0) // exit with code 0 (success)
process.exit(1) // exit with code 1 (failure)
process.pid // process ID
process.version // 'v20.x.x'
process.memoryUsage().heapUsed // bytes currently used in V8 heap
process.on('SIGTERM', handler) // graceful shutdown on termination signal
process.on('uncaughtException', handler) // last-resort error: log + exit(1)
process.on('unhandledRejection', handler) // unhandled Promise rejection: log + exit(1)File system (fs/promises)
TS
import fs from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
// ESM equivalent of __dirname:
const __dirname = path.dirname(fileURLToPath(import.meta.url))
await fs.readFile('./data.txt', 'utf8') // string
await fs.readFile('./image.png') // Buffer
await fs.writeFile('./out.txt', 'content', 'utf8')
await fs.appendFile('./log.txt', 'line
')
await fs.mkdir('./dir', { recursive: true }) // creates parents
await fs.rm('./dir', { recursive: true, force: true }) // delete dir
await fs.rename('./old.txt', './new.txt')
await fs.copyFile('./src.txt', './dst.txt')
await fs.stat('./file.txt') // { size, mtime, isFile() }
await fs.readdir('./dir', { withFileTypes: true }) // Dirent[] — check .isFile()
path.join('/a', 'b', 'c.txt') // '/a/b/c.txt'
path.resolve('src', 'index.ts') // absolute path from cwd
path.extname('file.ts') // '.ts'
path.basename('path/file.ts') // 'file.ts'
path.dirname('path/file.ts') // 'path'HTTP server and fetch
TS
import http from 'node:http'
// Minimal server:
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ ok: true }))
})
server.listen(3000)
// Graceful shutdown:
server.close(() => process.exit(0))
// Built-in fetch (Node 18+):
const res = await fetch('https://api.example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'value' }),
signal: AbortSignal.timeout(5000),
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()Streams
TS
import fs from 'node:fs'
import { pipeline } from 'node:stream/promises'
import { createGzip } from 'node:zlib'
// Pipe readable → transform → writable (handles backpressure + error propagation):
await pipeline(
fs.createReadStream('./input.txt'),
createGzip(),
fs.createWriteStream('./output.txt.gz')
)
// Read stream into string:
async function streamToString(readable: NodeJS.ReadableStream): Promise<string> {
const chunks: Buffer[] = []
for await (const chunk of readable) chunks.push(Buffer.from(chunk))
return Buffer.concat(chunks).toString('utf8')
}Child processes
TS
import { exec, execFile, spawn } from 'node:child_process'
import { promisify } from 'node:util'
const execAsync = promisify(exec)
// Simple command — returns stdout/stderr as strings:
const { stdout } = await execAsync('git log --oneline -5')
// Spawn for streaming output or large output:
const child = spawn('node', ['worker.js'], { stdio: 'pipe' })
child.stdout.on('data', (chunk) => process.stdout.write(chunk))
child.on('close', (code) => console.log('Exit code:', code))
// execFile — preferred over exec when path is user-controlled (no shell injection):
const { stdout: out } = await promisify(execFile)('/usr/bin/ls', ['-la', '/tmp'])Never pass unsanitized user input to exec() — it runs through a shell and enables command injection; use execFile() or spawn() with an args array instead
`exec('ls ' + userInput)` passes the full string to `/bin/sh -c`, so `userInput = '; rm -rf /'` runs as `ls ; rm -rf /`. `execFile('/bin/ls', [userInput])` passes `userInput` as a literal argument to `ls` — the shell never sees it. Always use `execFile` or `spawn` with separate `args` arrays when any part of the command comes from user input.
Crypto
TS
import { randomUUID, randomBytes, createHash, createHmac, timingSafeEqual } from 'node:crypto'
import { scrypt, scryptSync } from 'node:crypto'
randomUUID() // 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
randomBytes(32).toString('hex') // 64-char hex string (cryptographic random)
createHash('sha256').update('data').digest('hex')
createHmac('sha256', 'secret').update('data').digest('hex')
// Timing-safe comparison (prevents timing attacks):
const a = Buffer.from(hmacA)
const b = Buffer.from(hmacB)
if (a.length === b.length && timingSafeEqual(a, b)) { /* match */ }
// Password hashing (async — use bcrypt for passwords in practice):
scrypt('password', 'salt', 64, (err, derivedKey) => {
const hash = derivedKey.toString('hex')
})Worker threads
TS
import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads'
if (isMainThread) {
const worker = new Worker(__filename, { workerData: { n: 40 } })
worker.on('message', (result) => console.log('Result:', result))
worker.on('error', (err) => console.error(err))
} else {
// Runs in the worker thread:
const { n } = workerData
const result = fibonacci(n) // CPU-heavy work doesn't block the main event loop
parentPort!.postMessage(result)
}
function fibonacci(n: number): number {
return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)
}Useful one-liners
TS
// Deep clone (Node 17+):
const clone = structuredClone(original)
// Sleep (async delay):
await new Promise(resolve => setTimeout(resolve, 1000))
// Parallel async calls:
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()])
// First successful (ignore individual failures):
const result = await Promise.any([tryPrimary(), tryFallback()])
// All or reject on first failure:
const results = await Promise.allSettled([...])
// Read JSON file:
const data = JSON.parse(await fs.readFile('./data.json', 'utf8'))
// Write JSON file:
await fs.writeFile('./data.json', JSON.stringify(data, null, 2))
// Chunk an array for batch processing:
const chunks = <T>(arr: T[], size: number): T[][] =>
Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => arr.slice(i * size, i * size + size))Next
Avoid the pitfalls that catch experienced developers: [Common Mistakes to Avoid](/nodejs/common-mistakes).