os.availableParallelism()

Returns an estimate of how much parallelism the process can actually use, honouring CPU limits.

Signature
os.availableParallelism()
  • Added in Node.js v19.4.0, v18.14.0

Return value

integerAn estimate of the default amount of parallelism the program should use. Always greater than zero.

os.availableParallelism() answers the question people wrongly ask os.cpus(): how many things can this process usefully run at once? It is a thin wrapper over libuv's uv_available_parallelism(), which consults the CPU affinity mask and the cgroup CPU quota before falling back to the number of logical CPUs the machine reports.

When to reach for it

Any time you are choosing a number of workers, threads, forks or concurrent tasks: a worker_threads pool, a cluster fork count, the concurrency of a job runner, the -j of a build step you shell out to. In a Kubernetes pod with cpu: "2" it returns 2 while os.cpus().length returns whatever the node has, which is the difference between a pool that works and one that thrashes.

What trips people up

It is an estimate, not a hard limit — nothing stops you exceeding it, and for I/O-bound work you usually should. Reserve it for CPU-bound sizing. It is also relatively recent: on Node 18 you need 18.14.0 or newer, so libraries supporting older runtimes typically write (os.availableParallelism?.() ?? os.cpus().length). The value is read at call time, so a container resized while the process runs is not reflected in numbers you cached at startup.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Decide how many worker_threads to start for a CPU-bound transform
  • Set the fork count for a cluster-based HTTP server inside a container
  • Choose the concurrency limit of a batch image or video processing queue

Frequently asked questions

What is the difference between os.availableParallelism() and os.cpus().length?

os.availableParallelism() accounts for CPU affinity masks and container CPU quotas, while os.cpus().length simply counts every logical core the kernel exposes. Inside a container limited to 2 CPUs on a 32-core host the first returns 2 and the second returns 32, so only the first is safe for sizing a pool.

Which Node.js version added os.availableParallelism()?

It was added in v19.4.0 and backported to v18.14.0. On earlier releases the property is undefined, so guard with typeof os.availableParallelism === 'function' and fall back to os.cpus().length when you still support Node 16 or early 18.x.

Should I start exactly availableParallelism() workers?

For CPU-bound work, start that many or one fewer so the main thread keeps a share. For I/O-bound work the number is not a ceiling at all — network and disk concurrency can safely run far higher, so pick that limit from your downstream service's capacity instead.

More examples

Size a CPU-bound task pool

The output shows the clamping in action: the size never drops below 1 even on a single-CPU container, and the cap keeps a 96-core host from spawning 95 workers. The chunk figure is how many jobs each worker would receive under an even static split.

Example · javascript
const os = require('node:os');

function poolSize({ reserveMain = true, max = Infinity } = {}) {
  const base = os.availableParallelism();
  const size = reserveMain ? base - 1 : base;
  return Math.min(max, Math.max(1, size));
}

console.log('default pool:', poolSize());
console.log('capped at 4:', poolSize({ max: 4 }));
console.log('no reservation:', poolSize({ reserveMain: false }));

// Split 100 CPU-bound jobs across that pool.
const jobs = Array.from({ length: 100 }, (_, i) => i);
const n = poolSize();
const chunk = Math.ceil(jobs.length / n);
console.log('chunk size per worker:', chunk);

Feature-detect on older runtimes

On Node 22 the function is present and the first branch runs. The fallback line is what keeps the same code alive on Node 16 or an early 18.x, where calling os.availableParallelism() directly would throw a TypeError saying it is not a function.

Example · javascript
const os = require('node:os');

// availableParallelism landed in v19.4.0 / v18.14.0.
const parallelism =
  typeof os.availableParallelism === 'function'
    ? os.availableParallelism()
    : os.cpus().length || 1;

console.log('node version:', process.versions.node);
console.log('function present:', typeof os.availableParallelism === 'function');
console.log('parallelism in use:', parallelism);

Compare against the raw core count

On an unrestricted machine both numbers match and the else branch prints. Run the same script inside a container started with --cpus=2 on a larger host and the two diverge, which is exactly the case where sizing a pool from os.cpus().length would oversubscribe the CPU.

Example · javascript
const os = require('node:os');

const visible = os.cpus().length;
const usable = os.availableParallelism();

console.log('cores visible to the kernel:', visible);
console.log('parallelism available to us:', usable);

if (usable < visible) {
  console.log('restricted: a quota or affinity mask is in effect');
  console.log('oversubscription avoided:', visible - usable);
} else {
  console.log('unrestricted: this process can use every core');
}

Discussion

  • Be the first to comment on this lesson.