NodeJSNode.js Cheat Sheet

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).