Technology handbook
Node.js Packages — Modules, Libraries & Middleware
121 named things in the Node ecosystem: every core module, the packages you actually install, and the middleware that goes in front of a request.
- Topics
- 121
- Sections
- 10
Core modules
node:fs
File system access in callback, promise (fs/promises) and sync flavours. Prefer the promise API and avoid the sync one on a request path.
- Files and directories are read and written, sync, callback or promise.
- The promise API is what keeps file work off the callback style.
- A synchronous call blocks the event loop for its whole duration.
node:path
Joins, resolves and parses paths with the host separator. path.posix and path.win32 force a specific convention.
- Paths are joined, resolved and parsed per platform.
- Separators and drive roots differ, which string concatenation ignores.
- resolve produces an absolute path; join merely concatenates segments.
node:url
The WHATWG URL and URLSearchParams, plus fileURLToPath for turning import.meta.url into a real path.
- URLs are parsed and constructed to the WHATWG standard.
- It also converts between file paths and file URLs.
- Module metadata gives a URL, not a path, which is a common trip-up.
node:os
Host facts: CPU count, memory, platform, tmpdir and network interfaces. os.cpus().length sizes worker pools.
- Platform, CPU, memory and network details are reported.
- CPU count is the usual basis for sizing a worker pool.
- In a container it reports the host, not the container's limits.
node:util
promisify, callbackify, inspect, parseArgs and styleText. The junk drawer that is mostly useful.
- Promisify, inspect, text encoding and deprecation helpers live here.
- promisify adapts a callback API without wrapping it by hand.
- inspect is for humans; it is not a serialisation format.
node:events
EventEmitter, plus once() and on() helpers that bridge events into promises and async iterators.
- The emitter pattern underlies most of the standard library.
- Almost every stream and server is an emitter.
- An error event with no listener throws rather than being ignored.
node:stream
Readable, Writable, Duplex and Transform, with pipeline and finished for correct teardown.
- Readable, writable, duplex and transform streams process data incrementally.
pipeline is preferred over .pipe() because it handles errors and cleanup.- After a
.pipe() error each stream must be closed manually to avoid a leak.
node:buffer
Fixed-length byte sequences, encoding conversion and Blob. A Uint8Array subclass, so it interoperates with web APIs.
- Raw bytes are represented and converted between encodings.
- It is what file, socket and crypto APIs actually exchange.
- Slicing shares memory rather than copying it.
node:process
argv, env, exit codes, signals, cwd() and nextTick. Available as a global but importable for clarity.
- Arguments, environment, exit and signals are accessed here.
- It is the boundary between the program and its operating system.
- Mutating the environment at runtime does not reach child processes already started.
node:console
The familiar logger, plus console.table and constructible Console instances bound to any stream.
- Formatted output goes to stdout and stderr.
- It can be constructed against any stream, not just the defaults.
- Writing to a file descriptor can be synchronous and therefore blocking.
node:timers
setTimeout and friends; timers/promises gives awaitable versions with AbortSignal support.
- Timeouts, intervals and immediates schedule future work.
- The promises variant integrates cleanly with async code.
- A timer keeps the process alive until it is cleared or unreferenced.
node:querystring
Legacy query parsing. URLSearchParams is the modern replacement and handles encoding correctly.
- Legacy query strings are parsed and serialised.
- It predates URLSearchParams and behaves differently.
- URLSearchParams is the standard replacement for new code.
node:string_decoder
Decodes buffers to strings without splitting multi-byte characters across chunk boundaries.
- Byte chunks decode to text without splitting a character.
- A multi-byte character can straddle two chunks.
- Decoding each chunk independently corrupts exactly those characters.
node:assert
Runtime assertions, including deepStrictEqual. assert/strict makes strict comparison the default.
- Invariants are checked and throw when violated.
- The strict mode is the one worth using, as it avoids coercion.
- It is a debugging aid, not a validation library for user input.
node:module
createRequire, register for loader hooks, isBuiltin and the module resolution surface.
- The module system is inspected and extended.
- It exposes resolution and the ability to create a require.
- Hooking it affects the whole process, including dependencies.
node:v8
Heap statistics, snapshots and serialize/deserialize for structured cloning to a buffer.
- Engine statistics, heap snapshots and serialisation are exposed.
- A heap snapshot is what a memory leak investigation needs.
- Taking one pauses the process and produces a large file.
node:vm
Compiles and runs code in a separate V8 context. Not a security sandbox on its own.
- Code runs in a separate compilation context.
- It is useful for evaluating templates and configuration.
- It is not a security sandbox, whatever it appears to offer.
node:async_hooks
AsyncLocalStorage for request-scoped context that survives await boundaries without threading arguments.
- Asynchronous resources are tracked across their lifetime.
- AsyncLocalStorage is what propagates request context without passing it.
- The tracking has a measurable performance cost.
node:perf_hooks
performance.now, marks, measures and PerformanceObserver for timing work precisely.
- Timings and performance entries are measured precisely.
- Event-loop delay is the measurement that reveals blocking work.
- Observers must be disconnected or they accumulate entries.
node:diagnostics_channel
A publish/subscribe channel libraries use to emit trace events without a logging dependency.
- Named channels publish diagnostic events with near-zero cost when unused.
- Publishing costs nothing until something subscribes.
- It is a diagnostics mechanism, not an application event bus.
node:trace_events
Enables V8 and Node trace categories, written out for Chrome's trace viewer.
- Low-level runtime activity is recorded to a trace file.
- It shows engine and libuv behaviour no application log can.
- The output is large and needs a viewer to be readable.
node:inspector
Programmatic access to the V8 inspector protocol — CPU profiles and heap snapshots from inside the process.
- The debugging protocol is controlled from within the process.
- It is how a profile or heap snapshot is captured programmatically.
- Opening it exposes full control of the process.
node:repl
Builds a custom read-eval-print loop, useful for application consoles.
- An interactive evaluation loop is embedded in a program.
- It is a quick way to expose a debug console in a service.
- Anything reachable from the REPL is reachable by whoever opens it.
node:readline
Reads input line by line from a stream; readline/promises gives an awaitable question().
- Input is consumed line by line from a stream.
- It is the basis for prompts and for reading large files by line.
- The interface must be closed or the process stays alive.
node:tty
Detects whether a stream is a terminal and reports its size — the check behind colour output.
- Terminal characteristics are detected and controlled.
- Detecting a terminal is what decides whether colour is appropriate.
- Output redirected to a file is not a terminal.
node:zlib
gzip, deflate, brotli and zstd, as one-shot calls or as transform streams.
- Data is compressed and decompressed, including as streams.
- Streaming compression avoids holding both forms in memory.
- Decompressing untrusted input can expand to exhaust memory.
node:sqlite
A built-in synchronous SQLite driver, so simple persistence needs no native dependency.
- An embedded SQL database ships with the runtime.
- No dependency and no server is the entire appeal.
- It is a single file, so concurrent writers contend.
Testing & diagnostics
node:test
The built-in test runner: describe, it, mocking, snapshots, coverage and watch mode, with no dependency.
- A test runner is built into the runtime.
- It removes a dependency for projects with modest needs.
- Its ecosystem is far smaller than the established runners.
@opentelemetry/sdk-node
Vendor-neutral tracing, metrics and logs with auto-instrumentation for the common libraries.
- Traces and metrics are emitted in a vendor-neutral format.
- Neutrality is what avoids re-instrumenting per vendor.
- Automatic instrumentation adds measurable overhead.
clinic
Diagnoses performance problems — event loop delay, flame graphs and GC pressure.
- Performance problems are diagnosed with guided profiling.
- It identifies whether the bottleneck is CPU, I/O or the loop.
- It is a diagnostic tool, not something to run in production.
autocannon
HTTP benchmarking to find where throughput actually falls over.
- HTTP load is generated for benchmarking.
- Measuring under load is what reveals a saturation point.
- Benchmarking against a local machine measures the client too.
supertest
Drives an HTTP server in-process from a test, with fluent assertions on the response.
- HTTP assertions run against an application instance.
- No port needs binding, which keeps tests isolated.
- It exercises the app, not the deployment around it.
nock
Intercepts outbound HTTP in tests so suites do not depend on the network.
- Outbound HTTP is intercepted and mocked.
- Mocking at the HTTP layer keeps the client code real.
- An unmatched request fails in a way that can be confusing.
msw
Request mocking at the network layer, with one set of handlers shared by tests and the browser.
- Requests are intercepted with handlers shared across environments.
- One set of handlers serves both browser and Node tests.
- Handlers must be kept in step with the real API.
Streams & buffers
stream/promises
Awaitable pipeline and finished, which is how you get correct error propagation in async code.
pipeline awaits a chain of streams and cleans them up on failure.- With
.pipe(), a Readable error does not close the Writable, which leaks. - Its
end option defaults to true, and transform streams are always ended.
stream/web
The WHATWG ReadableStream and WritableStream, for code shared with browsers and edge runtimes.
- Web-standard streams interoperate with the Node ones.
- Standard streams are what fetch bodies actually are.
- The two families need explicit conversion between them.
Readable.from
Turns any iterable or async iterable into a readable stream in one call.
- An iterable or async iterable becomes a readable stream.
- It is the bridge from a generator into the stream world.
- The source is consumed lazily, so it must remain valid.
stream.compose
Combines several streams into one duplex, so a pipeline can be passed around as a single value.
- Several streams combine into a single duplex stream.
- Composition is what makes a pipeline reusable as one unit.
- Errors surface on the composed stream rather than the parts.
Backpressure
write() returning false means stop and wait for drain. Ignoring it is how memory blows up.
write() returns false once the internal buffer reaches the highWaterMark.- Further writes should stop until the
'drain' event says it is safe to resume. - Ignoring the return value is what makes memory grow without bound.
Object mode
Streams that carry arbitrary values rather than bytes, which is how most parsing pipelines work.
- A stream carries arbitrary objects rather than bytes.
- It lets records flow through a transform pipeline.
- The high-water mark counts objects, not bytes.
Networking modules
node:http
The HTTP/1.1 server and client. Every Node web framework is a layer over createServer.
- HTTP servers and clients are built at the protocol level.
- It is the layer every framework here is built upon.
- Nothing is handled for you, including body parsing and routing.
node:https
HTTP over TLS, with certificate and SNI options passed through to node:tls.
- HTTP over TLS is served and requested.
- Certificate and cipher configuration lives here.
- Disabling certificate verification silently removes the security.
node:http2
HTTP/2 with multiplexed streams and server push, plus a compatibility mode for http handlers.
- Multiplexed streams share a single connection.
- Multiplexing removes head-of-line blocking between requests.
- It requires a different server API than HTTP/1.
node:net
Raw TCP and Unix domain sockets, underneath everything in http.
- TCP servers and clients are created directly.
- It is the substrate for protocols above TCP.
- Message framing is the application's problem, not the socket's.
node:dgram
UDP sockets for protocols where dropping a packet beats waiting for one.
- UDP datagrams are sent and received.
- It suits metrics and discovery where loss is acceptable.
- There is no delivery guarantee and no ordering.
node:dns
Name resolution, with dns/promises and explicit resolve* calls that bypass the OS cache.
- Names are resolved through the system or directly.
- The resolver choice changes caching and failure behaviour.
- The default lookup can block a thread in the pool.
node:tls
TLS sockets, certificate handling, ALPN and mutual authentication.
- Encrypted sockets are created and configured.
- It underlies HTTPS and any other secured protocol.
- Certificate chain and hostname checks must both be correct.
fetch
The global WHATWG fetch, backed by undici, with AbortSignal.timeout for deadlines.
- The standard HTTP client is built into the runtime.
- No dependency is needed for ordinary requests.
- It does not reject on 404 or 500, so the status must be read.
WebSocket
A global client-side WebSocket, so outbound realtime connections need no package.
- A standards-based client is available in the runtime.
- It removes a dependency for outbound websocket connections.
- Serving websockets still requires a library.
System & process
node:child_process
spawn, exec, fork and their sync forms. Prefer spawn with an argument array over exec with a string.
- External programs are spawned and their streams handled.
- Passing arguments as an array is what avoids shell injection.
- A child whose output is never read blocks when its pipe fills.
node:worker_threads
Real threads for CPU-bound JavaScript, with SharedArrayBuffer and MessagePort for transfer.
- JavaScript runs on additional threads with message passing.
- It is how CPU-bound work stops blocking the event loop.
- Each worker has its own heap, so data is copied or shared explicitly.
node:cluster
Forks one process per core sharing a listening socket. Largely superseded by a process manager.
- Multiple processes share a listening socket.
- It is how a single-threaded runtime uses several cores for I/O.
- Nothing is shared between workers except the socket.
Signals
SIGTERM and SIGINT handlers are where graceful shutdown starts — stop accepting, drain, exit.
- Operating system signals are observed and handled.
- Handling termination is what allows a graceful shutdown.
- Some signals cannot be caught, and handling can delay exit indefinitely.
process.exitCode
Setting it lets the event loop drain naturally, unlike process.exit() which truncates pending writes.
- The exit status is set without terminating immediately.
- Setting it lets pending work finish before the process ends.
- Calling exit directly discards buffered output.
Crypto & security
node:crypto
Hashing, HMAC, ciphers, key generation, signing and randomUUID. Wraps OpenSSL.
- Hashing, signing, encryption and random values are provided.
- It is the maintained implementation to prefer over any hand-rolled one.
- Choosing the wrong mode or reusing a nonce breaks the guarantee.
crypto.webcrypto
The standards-based SubtleCrypto API, portable to browsers and edge runtimes.
- The standard Web Crypto interface is available.
- Standard code then runs in both browser and server.
- Its API is promise-based and differs from the Node one.
timingSafeEqual
Constant-time buffer comparison — the only correct way to compare secrets and tokens.
- Two buffers are compared in constant time.
- Constant time is what prevents a timing side channel.
- It throws when lengths differ, which itself can leak.
scrypt / argon2
Password hashing built for slowness. Never store a password with a plain hash.
- Passwords are hashed with a deliberately slow function.
- Slowness is the defence; a fast hash is the vulnerability.
- Parameters must be tuned to the hardware and stored with the hash.
node:permission
The process permission model: --allow-fs-read, --allow-child-process and friends restrict what code may do.
- The process restricts its own filesystem and child-process access.
- It limits the blast radius of a compromised dependency.
- It is coarse and cannot replace running with least privilege.
Web frameworks
express
The long-standing minimal framework. Middleware chains, a router and a vast plugin ecosystem.
- The long-established minimal web framework.
- Its middleware ecosystem is the largest available.
- Async errors are not caught automatically without care.
fastify
Schema-first and fast, with JSON schema validation and serialisation built into the route definition.
- A performance-focused framework with schema-based validation.
- Schemas drive validation and serialisation together.
- Its plugin encapsulation model differs from Express middleware.
koa
Express's successor from the same authors: async middleware with a single ctx and no callbacks.
- A small framework built on async middleware.
- Its context object and downstream-upstream flow are the distinguishing idea.
- Almost everything is a separate package.
hono
Tiny, web-standards-based and runtime-portable — the same app runs on Node, Bun, Workers and Deno.
- A tiny framework built on web standards.
- Standards-first is what lets it run on many runtimes.
- Node-specific middleware does not apply.
@nestjs/core
The opinionated, decorator-driven framework covered in full by its own handbook.
- An opinionated framework with dependency injection and modules.
- Structure is imposed, which is what suits larger teams.
- It sits on Express or Fastify rather than replacing them.
h3
The minimal composable server behind Nitro and Nuxt, built on web-standard primitives.
- A minimal, composable HTTP framework.
- It is the server layer beneath Nitro and Nuxt.
- It is deliberately low level and assembles from utilities.
elysia
An end-to-end type-safe framework, Bun-first but Node-capable.
- An ergonomic, type-driven framework aimed at Bun.
- End-to-end type inference is its main draw.
- Its performance claims assume the Bun runtime.
restify
Aimed squarely at strict REST APIs, with built-in throttling and DTrace support.
- A framework aimed specifically at REST APIs.
- It leans toward operability with built-in throttling and metrics.
- Its ecosystem is much smaller than Express's.
polka
An Express-compatible router in a fraction of the code, for when the middleware ecosystem is not needed.
- A tiny Express-compatible router.
- Compatibility means most Express middleware still works.
- It provides routing and little else.
Middleware
cors
Sets the Cross-Origin Resource Sharing headers. Configure an explicit origin allowlist, never a blanket * with credentials.
- Cross-origin request headers are configured.
- Browsers enforce it, so it is not a server-side access control.
- A wildcard origin with credentials is rejected by browsers.
helmet
Sets a bundle of defensive HTTP headers — CSP, HSTS, frame options and more — in one call.
- Security-related response headers are set.
- Sensible defaults are applied without per-header work.
- A content security policy still has to be written deliberately.
body-parser
JSON, urlencoded, raw and text body parsing. Folded into Express 4.16+ as express.json().
- Request bodies are parsed into objects.
- Its functionality is now built into Express itself.
- Without a size limit a large body is a denial of service.
cookie-parser
Parses the Cookie header into req.cookies, with signed-cookie support.
- Cookies are parsed and signed cookies verified.
- Signing is what detects a tampered cookie.
- Signing is not encryption; the value is still readable.
express-session
Server-side sessions with a pluggable store. Use Redis in production, never the default memory store.
- Server-side sessions are kept with a cookie identifier.
- The store is what makes sessions survive a restart.
- The default memory store is unsuitable for production.
morgan
HTTP request logging in several preset formats, wired to any writable stream.
- HTTP requests are logged in configurable formats.
- It is the quickest way to get request visibility.
- Its text output is awkward to query compared with structured logs.
compression
gzip and brotli response compression, with a threshold so tiny bodies are left alone.
- Responses are compressed before being sent.
- It reduces transfer size at some CPU cost.
- Compressing an already compressed asset wastes both.
express-rate-limit
Request throttling per key, with stores for Redis so limits hold across instances.
- Requests per client are limited over a window.
- Limiting is what blunts brute force and scraping.
- The default memory store is per instance, not per cluster.
multer
multipart/form-data handling for file uploads, to disk or to memory.
- Multipart file uploads are parsed.
- Limits and destination are configured rather than assumed.
- Writing to disk without validation accepts whatever is sent.
passport
Pluggable authentication with several hundred strategies — OAuth, OIDC, SAML, local.
- Authentication strategies plug into a common interface.
- One interface covers hundreds of providers.
- Strategy quality and maintenance vary widely.
csurf / csrf-csrf
CSRF token issue and verification for cookie-authenticated form posts.
- Cross-site request forgery tokens are issued and verified.
- A token is what proves the request came from your own page.
- csurf is deprecated, which is why the alternative exists.
serve-static
Serves a directory with correct caching and range headers. express.static is this package.
- Files are served from a directory.
- Caching headers are configured here rather than per file.
- Serving a directory that contains secrets exposes them.
http-proxy-middleware
Proxies matched routes to another origin, with path rewriting and websocket support.
- Requests are proxied to another service.
- It is the usual way to avoid CORS during development.
- An unrestricted proxy can be used to reach internal hosts.
express-validator
Request validation and sanitisation built on validator.js, declared per route.
- Request fields are validated with chained rules.
- Validation sits as middleware before the handler.
- Results must be checked explicitly or the rules do nothing.
connect-timeout
Aborts requests that exceed a deadline so a slow dependency cannot pin a worker.
- A request exceeding a duration is failed.
- A bound is what stops one slow request holding a connection.
- The handler still runs unless it checks the timeout itself.
Data & ORM
prisma
Schema-first ORM with a generated, fully typed client and a first-class migration workflow.
- A schema generates a typed client for relational data.
- The client is generated, so it cannot drift from the schema.
- It sits between you and SQL, which sometimes matters.
drizzle-orm
A SQL-shaped TypeScript ORM: queries read like SQL and infer their result types.
- A SQL-first builder infers types from a TypeScript schema.
- The query resembles the SQL that will run.
- The relational and core query APIs return different shapes.
typeorm
Decorator-based ORM with entities, repositories and migrations. Nest's traditional default.
- Entities are decorated classes with repositories and migrations.
- It supports both active record and data mapper styles.
- Its behaviour across dialects is less uniform than it appears.
sequelize
A mature promise-based ORM for Postgres, MySQL, SQLite and SQL Server.
- A long-established ORM with models and associations.
- Maturity means most problems have a documented answer.
- Its TypeScript support is weaker than newer alternatives.
knex
A query builder rather than an ORM, plus a migration and seeding runner.
- A query builder without an object mapping layer.
- It generates SQL while leaving the data model to you.
- Results are untyped unless types are declared separately.
pg
The Postgres driver: connection pooling, cursors, LISTEN/NOTIFY and COPY streams.
- The PostgreSQL driver with pooling and typed results.
- Most higher-level tools are built on it.
- Pool size multiplied by instances is what the server sees.
mysql2
The MySQL driver with prepared statements and a promise interface.
- A MySQL driver with promises and prepared statements.
- Prepared statements bind parameters rather than interpolating.
- Its type conversion differs subtly from the older driver.
better-sqlite3
Synchronous SQLite bindings, faster than the async alternatives for embedded workloads.
- A synchronous SQLite binding.
- Synchronous access is genuinely faster for an embedded database.
- Every call blocks the event loop, so long queries hurt.
ioredis
A full Redis client with cluster, sentinel, pipelining and Lua scripting.
- A Redis client with cluster and sentinel support.
- It handles reconnection and failover for you.
- Commands queued while disconnected can pile up unbounded.
kysely
A type-safe SQL query builder that infers result types from your schema definition.
- A type-safe SQL query builder.
- Types are inferred from a declared database interface.
- The interface must be kept in step with the real schema.
zod
Schema declaration and validation that produces TypeScript types by inference.
- Runtime schemas infer TypeScript types.
- One declaration gives both the check and the type.
- Parsing has a cost on very hot paths.
dotenv
Loads .env into process.env. Node's own --env-file flag now covers the common case.
- Variables load from a file into the environment.
- It is a development convenience, not a secret store.
- A committed env file is a leaked credential.
pino
Very fast structured JSON logging, with transports kept on a worker thread.
- Structured JSON logging with very low overhead.
- Structured output is what makes logs queryable.
- Pretty printing is for development and costs significantly.
winston
Multi-transport logging with formats, levels and per-transport filtering.
- Logging with configurable transports and formats.
- Multiple destinations are its main strength.
- It is heavier than the performance-focused alternatives.
undici
The HTTP client behind global fetch, exposed directly for pools, interceptors and mock agents.
- The HTTP client that backs the runtime's fetch.
- Using it directly exposes pooling and connection control.
- Its lower-level API is easy to misuse.
axios
A promise HTTP client with interceptors, cancellation and automatic JSON handling.
- A widely used HTTP client with interceptors.
- Interceptors are what centralise auth and retry logic.
- It is a dependency for what fetch now does natively.
got
An HTTP client with retries, hooks, pagination and streaming as first-class features.
- An HTTP client with retries and hooks built in.
- Retry and timeout behaviour is configured declaratively.
- It is Node-only, unlike the standard client.
commander
Declarative CLI argument parsing with subcommands, options and generated help.
- Command-line interfaces are declared with options and subcommands.
- Declaring the interface generates the help text.
- Complex nesting becomes hard to follow.
yargs
CLI parsing with rich validation, middleware and command modules.
- Command-line parsing with validation and completion.
- It handles rich argument shapes and coercion.
- Its fluent API is large and easy to misapply.
chalk
Terminal colour and style with automatic capability detection.
- Terminal output is coloured and styled.
- It detects colour support rather than assuming it.
- Colour codes in redirected output become noise.
ora
Terminal spinners for long-running CLI work.
- A terminal spinner shows progress for long work.
- It gives feedback where output would otherwise stall.
- It assumes a terminal and misbehaves in CI logs.
inquirer
Interactive command-line prompts: lists, confirms, checkboxes and editors.
- Interactive prompts collect input on the command line.
- It covers lists, confirmations and validated input.
- A prompt in a non-interactive environment hangs.
date-fns
Immutable, tree-shakeable date functions, imported one at a time.
- Immutable date utilities are imported individually.
- Per-function imports are what keep the bundle small.
- Time zone support requires a separate package.
luxon
Timezone-aware date handling built on the Intl APIs.
- Dates and times with first-class time zone support.
- Zone handling is what it exists to get right.
- Its objects are not interchangeable with native dates.
uuid
RFC-compliant UUID generation. For v4 specifically, crypto.randomUUID() needs no package.
- Standard universally unique identifiers are generated.
- Version 4 is random; version 7 is time-ordered.
- Random identifiers index poorly as a primary key.
nanoid
Short, URL-safe, collision-resistant identifiers.
- Short, URL-safe random identifiers are generated.
- Shorter output suits identifiers that appear in URLs.
- A shorter length raises collision probability.
lodash-es
The collection and object utility belt, in ESM so unused functions are dropped.
- Utility functions ship as ES modules.
- Module format is what allows unused functions to be dropped.
- Much of it is now native JavaScript.
bullmq
Redis-backed job queues with retries, rate limits, repeatable jobs and flows.
- Redis-backed job queues with retries and scheduling.
- Durability is what separates it from an in-process emitter.
- Redis becomes a hard dependency and a failure point.
node-cron
In-process cron scheduling. A real scheduler is better once you run more than one instance.
- Scheduled tasks run inside the process.
- It needs no external scheduler for simple cases.
- Every instance runs the job unless a lock prevents it.
nodemailer
SMTP email sending with attachments, templates and pooled connections.
- Email is sent through SMTP or a provider.
- It is the standard way to send mail from Node.
- Deliverability depends on domain configuration, not the library.
ws
A fast, spec-compliant WebSocket server and client.
- A minimal, fast websocket server and client.
- It is the implementation most other libraries build on.
- Broadcast, rooms and reconnection are yours to write.
socket.io
Realtime messaging with rooms, acknowledgements, fallbacks and reconnection.
- Real-time messaging with rooms, fallback and reconnection.
- Reconnection and rooms are what it adds over raw websockets.
- It is a protocol of its own, so both ends must use it.
jsonwebtoken / jose
JWT signing and verification; jose also covers JWE, JWK and the web-standard crypto.
- Tokens are signed and verified.
- jose is standards-complete and covers modern algorithms.
- Verifying without pinning the algorithm is a known vulnerability.
sharp
High-performance image resizing and format conversion over libvips.
- Images are resized and converted at high speed.
- It uses a native library, which is the source of the speed.
- Native binaries complicate cross-platform deployment.
archiver
Streaming zip and tar creation without buffering the whole archive.
- Archives are created as a stream.
- Streaming is what allows an archive larger than memory.
- The output stream must be finalised or the file is truncated.
tsx
Runs TypeScript directly, for scripts and development servers.
- TypeScript runs directly without a build step.
- It makes scripts and development runs immediate.
- It transpiles without type checking, so errors still pass.
pm2
Process manager: clustering, restarts, log rotation and zero-downtime reloads.
- Processes are supervised, clustered and restarted.
- It supplies supervision where no orchestrator exists.
- Under a container orchestrator it duplicates responsibility.
nodemon
Restarts a process when watched files change. Node's own --watch now covers most uses.
- The process restarts when files change.
- It is the simplest development watch loop.
- A full restart is slower than an in-process reload.