Node hands async fs, dns.lookup, async zlib and async crypto calls, and native addons such as bcrypt and sharp, to libuv's threadpool. The pool has four threads whatever the machine, and its size is read from UV_THREADPOOL_SIZE the first time it is used, so only the environment can change it. Nub sets the variable when it starts Node.

nub server.ts                        # pool sized to the cores, 16 on a 16-vCPU box
node server.ts                       # pool of 4
UV_THREADPOOL_SIZE=6 nub server.ts   # your value, used as is

The size is the larger of four and the cores available to the process, so a container gets its cgroup quota rather than the host's core count. A container's thread limit caps it. Windows stops at eight.

Read the full docs for the threadpool on docs.libuv.org.

Priority

On Linux the threads beyond the first four run at nice 10, about a tenth of the scheduler weight of a normal thread. On an idle box they run at full speed. Under contention they yield most of the CPU to the other work on the machine.

Child processes

A process your app spawns, including a cluster worker, starts with Node's default of four. A child that runs through nub is sized again. A UV_THREADPOOL_SIZE you set, in the shell or in an env file, is inherited as under Node.

Opting out

A UV_THREADPOOL_SIZE of your own wins. --node and NODE_COMPAT leave the pool at Node's default.