workerpool

A lightweight thread pool for offloading CPU-intensive functions to worker threads, child processes, or web workers, on both Node.js and in the browser.

Library
npm
v10.0.3
2,309stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
70/100Good
Development Activity84
Maintenance40
Community56
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture80
Code Quality72
Innovation75
Learning Curve65

workerpool solves the single-threaded-event-loop problem in JavaScript: a CPU-heavy function blocks everything else until it finishes, whether that is a browser tab freezing on user input or a Node.js server stalling every other request. It implements the classic thread pool pattern, letting an application hand off individual functions to a managed pool of workers and get the result back through a familiar promise-based API, without having to write worker-thread boilerplate by hand.

The library runs unmodified across Node.js worker_threads, Node.js child_process, and browser Web Workers, auto-detecting the right backend for the environment (or letting the caller pin one explicitly). Beyond simple offloading, it supports dedicated worker scripts accessed via a generated proxy, cancellable and timeout-aware promises, transferable objects for zero-copy data hand-off, and hooks for allocating and releasing per-worker resources — all with zero runtime dependencies.

What You Get

  • A pool() factory that creates and manages a pool of workers with configurable min/max size, queue strategy (FIFO or LIFO), and queue-size limits
  • Dynamic function offloading via pool.exec(fn, args) — pass a plain function and its arguments, get a promise back, no separate worker file required
  • Dedicated worker scripts via pool.exec('methodName', args) plus a generated pool.proxy() object for calling registered worker methods as if they were local
  • An enhanced Promise implementation with .cancel() and .timeout(delay), so any running task can be aborted or bounded without killing the whole pool
  • Automatic backend selection across worker_threads, child_process, and Web Workers, with an explicit workerType override when a fixed strategy is needed
  • Support for transferable objects (Transfer) to move typed arrays and buffers between main thread and worker without copying
  • Lifecycle hooks (onCreateWorker, onTerminateWorker, worker-side addAbortListener) for allocating or releasing per-worker resources and enabling graceful, recoverable termination

Common Use Cases

  • Offloading a CPU-heavy computation (image processing, data crunching, cryptographic hashing) from a Node.js server so it keeps answering other requests
  • Keeping a browser UI responsive while running an expensive synchronous algorithm by moving it to a Web Worker with the same API used on the server
  • Running a fixed set of long-lived worker scripts (e.g. per-connection or per-job handlers) accessed through a typed proxy instead of raw message passing
  • Bounding and cancelling slow or runaway tasks in a task-processing pipeline using per-task .timeout() and .cancel()
  • Parallelizing independent batches of work (e.g. per-file transforms in a build tool) across all available CPU cores

Under The Hood

Architecture workerpool separates scheduling from execution: Pool owns a task queue (pluggable FIFO or LIFO strategy via queues.js) and a list of WorkerHandler instances, matching queued tasks to idle workers in _next()/_getWorker() and lazily spinning up new workers up to maxWorkers. WorkerHandler hides the actual transport — worker_threads, child_process, or a browser Worker — behind one interface, choosing the backend via environment.js’s platform detection unless a workerType is forced. A custom Promise implementation (Promise.js) layers cancellation and timeout support on top of standard promise semantics, and is threaded all the way through task execution so a queued-but-not-yet-started task can still be timed out or cancelled correctly. This is a clean, single-responsibility layering (scheduling vs. transport vs. promise semantics vs. queue strategy) that would let a new backend (e.g. a future runtime’s worker primitive) be added by implementing one more setupXWorker function.

Tech Stack The library itself is authored in plain CommonJS JavaScript with JSDoc type annotations (no hand-written TypeScript), and ships with zero runtime dependencies — type declarations are generated at build time by pointing tsc at the JSDoc-annotated source. The build pipeline uses Rollup to produce browser bundles (dist/workerpool.js), targets Node’s built-in worker_threads and child_process modules alongside the browser Worker/Blob APIs for an embeddable worker script, and is tested with Mocha plus c8 for coverage.

Code Quality The test suite covers the pool, the worker handler, the custom promise, the queue implementations, environment detection, and debug-port allocation, and CI (GitHub Actions) runs the full suite across three current Node.js major versions. Tests consistently clean up pools in afterEach to avoid leaking worker processes between runs. Error handling favors explicit, purpose-built error types (TerminateError, Promise.CancellationError, Promise.TimeoutError) rather than generic thrown strings, and JSDoc annotations combined with a tsc --emitDeclarationOnly step give consumers real .d.ts types without a TypeScript rewrite. No dedicated linter or formatter config is present in the repository, which is the main gap relative to a fully modern JS toolchain.

What Makes It Unique Most worker-pool libraries pick one backend and one environment; workerpool’s distinguishing choice is treating worker_threads, child_process, and Web Workers as interchangeable transports behind identical pool()/worker() call sites, so the same application code can run offloaded functions in Node.js or the browser. It layers cancellation and timeout semantics directly onto the promises it returns rather than exposing a separate control API, and it goes further than most alternatives by supporting recoverable worker termination through worker-side abort listeners, letting a worker clean up and stay alive instead of always being killed outright.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search