node-tls-clientLatest version on npm

Concurrency

How many requests run in parallel, and how to raise it.

Requests are asynchronous: start as many as you like with Promise.all. How many actually run at the same time is decided by Node's libuv threadpool.

// Run with: UV_THREADPOOL_SIZE=64 node concurrency.mjs
await initTLS({ concurrency: 64 }); // at most 64 requests in flight

const session = new Session({ timeout: 15_000 });
const urls = Array.from(
  { length: 20 },
  (_, i) => `https://httpbin.org/anything/${i}`,
);

// Start them all at once; up to UV_THREADPOOL_SIZE run in parallel,
// the rest wait in a queue.
const responses = await Promise.all(urls.map((url) => session.get(url)));
console.log(responses.map((r) => r.status)); // [ 200, 200, … ]

How it works

Each request runs inside the native library on a libuv threadpool thread and holds that thread for its whole round-trip, from connecting to the last byte of the body. So:

  • Parallelism = UV_THREADPOOL_SIZE. Node's default is 4. When it's unset, this package sets it to CPU cores × 2 at import time. libuv caps it at 1024.
  • Requests beyond that wait in a queue and start as threads free up. Nothing is dropped.
  • Native calls share the threadpool with Node's own fs, DNS, zlib and crypto work. Under sustained load with a small pool, those wait behind in-flight requests, so size the pool for both.

Raising the limit

Set UV_THREADPOOL_SIZE before Node starts:

UV_THREADPOOL_SIZE=64 node app.js

The import-time default only works if nothing used the threadpool before this package was imported (an fs.promises call, a DNS lookup, …). It also doesn't apply when your entry file is an ES module on Node 20, Node 22 before 22.18 or Node 24 before 24.3; a warning says so. Set it in the real environment for a guaranteed effect. Set UV_THREADPOOL_SIZE=4 to keep Node's default.

To remove the limit altogether, use the node-tls-client binary: its requests don't hold a thread, so every request you start runs at once.

initTLS({ concurrency })

concurrency caps how many requests are admitted to the native layer at once. It defaults to the threadpool size.

  • Values above UV_THREADPOOL_SIZE only queue and add no parallelism; a warning says so.
  • Each in-flight request reserves about 256 KiB of memory, so very high values cost RAM.
  • The maximum is 4096.
  • It's read once: calling initTLS() again with a different value has no effect until destroyTLS().

Lower it to limit memory or the load you put on a site; raise UV_THREADPOOL_SIZE to go faster.

Slow servers

Because a slow response keeps its thread busy until it finishes, slow endpoints use up the pool quickly. If throughput drops when a site gets slow, raise UV_THREADPOOL_SIZE and set a session timeout so stuck requests give their thread back.

Shutdown

destroyTLS() stops admitting requests, waits for the in-flight ones (each bounded by its own timeout), then frees native state.

On this page