node-pool
Promise-based generic resource pool for reusing or throttling expensive resources like database connections.
Repository Health
Technical Analysis
generic-pool (published on npm from the node-pool repository) is a Promise-based object pool for Node.js. Rather than tying itself to any specific resource type, it accepts a factory object with create, destroy, and optional validate functions, letting callers pool database connections, sockets, worker handles, or any other expensive-to-create object behind a uniform acquire/release API.
Internally the pool tracks resources through a small state machine (allocated, idle, invalid, returning, validation), backed by a doubly linked list deque for available resources and a priority queue for waiting borrowers. This gives it features that hand-rolled pooling code usually lacks: priority-based queueing for waiters, an idle-object evictor that can retire stale resources on a timer, configurable min/max pool sizing, and acquire/destroy timeouts.
The library has been a de facto standard in the Node ecosystem since 2010, widely used indirectly through database drivers and ORMs (such as Knex.js and Sequelize) that need connection pooling but don’t want to reimplement it themselves.
What You Get
createPool(factory, opts)constructor that wraps anycreate/destroy/validatefactory into a managed pool- Promise-based
acquire()/release()/destroy()API plus ause(fn)helper that acquires, runs a callback, and automatically releases or destroys the resource based on outcome - Priority queueing so borrowers can specify a relative priority when the pool is exhausted and callers must wait
- Configurable min/max pool size,
acquireTimeoutMillis/destroyTimeoutMillis, andmaxWaitingClientsto bound queue growth - Idle-object evictor that runs on a configurable interval to destroy resources that have sat unused past
idleTimeoutMillisorsoftIdleTimeoutMillis - Shipped TypeScript type definitions (
index.d.ts) for typed factories and pool instances without a separate@typespackage
Common Use Cases
- Pooling database client connections behind a driver or ORM that doesn’t ship its own pooling (many Knex.js and Sequelize dialect drivers use generic-pool internally)
- Throttling concurrent access to a rate-limited external API or headless-browser instance by capping
maxand queueing excess requests - Reusing worker processes or expensive native handles (e.g. image-processing workers) instead of spawning one per request
- Building a custom resource pool for an in-house protocol client where no existing pooling library fits the resource’s lifecycle
Under The Hood
Architecture
generic-pool is organized as a set of small, single-responsibility classes wired together by lib/Pool.js, an EventEmitter subclass that owns the pool’s lifecycle. PoolOptions validates and normalizes constructor options, factoryValidator enforces the required create/destroy shape before the pool will start, and pool state is tracked across five explicit stages (ALLOCATED, IDLE, INVALID, RETURNING, VALIDATION) defined in PooledResourceStateEnum. Available resources live in a Deque (backed by DoublyLinkedList/DoublyLinkedListIterator) so the pool can operate as either a FIFO queue or a LIFO stack depending on the fifo option, while waiting borrowers sit in a PriorityQueue that fans out into per-priority sub-queues. ResourceRequest and ResourceLoan (both built on a shared Deferred promise wrapper) represent, respectively, a pending acquire and an outstanding loan, and index.js assembles the whole thing by injecting the evictor, deque, and priority-queue classes into Pool’s constructor rather than hardcoding them — a seam that exists mainly to keep the core testable in isolation. The result is a compact but genuinely layered design: no single file exceeds a few hundred lines, and swapping the eviction policy or queue strategy doesn’t require touching the acquire/release logic.
Tech Stack
The library is plain CommonJS JavaScript with zero runtime dependencies, targeting Node >= 4 per package.json’s engines field, and ships hand-written TypeScript declarations (index.d.ts) validated via tsc --noEmit against a strict: false tsconfig.json. Tooling is intentionally minimal: ESLint with eslint-plugin-prettier enforces formatting as a lint error, and a Makefile drives make install/make lint/make test for both local development and the (now largely dormant) Travis CI matrix that tested against Node 6 through 11 on amd64 and ppc64le. There is no bundler, build step, or transpilation — the published package is the source as-is.
Code Quality
Tests run under tap against multiple focused suites (generic-pool-test.js, dedicated acquire/destroy-timeout tests, a doubly-linked-list test, a resource-request test, and a regression test tied to a specific GitHub issue), exercising acquire/release ordering, priority behavior, and timeout edge cases directly against the public API rather than through mocks. Several older tests are left commented out in place with explanatory notes rather than deleted, which is a minor rough edge but doesn’t affect what actually runs. Error handling is explicit throughout Pool.js — factory promise rejections are funneled through named factoryCreateError/factoryDestroyError events rather than swallowed, and public methods reject their returned Promises with typed errors from lib/errors.js (TimeoutError, etc.) instead of throwing generic ones. Naming is consistent and JSDoc comments annotate most public methods and constructor parameters, though the project’s own activity_status shows very low recent commit and release activity, meaning newer Node/V8 idioms aren’t reflected in the code.
API Design
The public surface is deliberately small: one factory contract (create/destroy/optional validate), one createPool entry point, and a handful of methods (acquire, release, destroy, use, start, ready, drain, clear). The use(fn) helper in particular removes the most common source of pooling bugs — forgetting to release or destroy a borrowed resource — by handling acquire/release/destroy automatically based on whether the supplied callback’s promise resolves or rejects. Priority queueing and eviction are opt-in via configuration rather than separate APIs, keeping the common case (just call acquire()/release()) free of ceremony, and the shipped .d.ts file means TypeScript consumers get typed factories and pool instances without any extra setup.
Used by 4 apps in this directory
GrowthBook
Developer Tools · Analytics · Monitoring
Open source feature flags, A/B testing, and warehouse-native experimentation that queries your existing data infrastructure—no data movement required.
overleaf
Collaboration · Productivity
Open-source, real-time collaborative LaTeX editor with sandboxed compilation and full TeXLive support for self-hosted academic and research teams.
Penpot
Design Tools
Open-source design platform with GPU-accelerated canvas, native design tokens, and MCP-powered AI workflows for teams that ship fast.
PostHog
Analytics · Monitoring · Developer Tools
The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.