How to create threads in nodejs
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Node.js is single-threaded at the JavaScript event-loop level, but that does not mean it cannot use threads. If you want to run JavaScript code in parallel, the modern API is worker_threads; if you only need non-blocking I/O, you usually do not need to create threads manually at all.
First: Know the Difference Between Concurrency and Parallelism
Node already handles many I/O operations concurrently through the event loop and the underlying libuv thread pool. That is why code such as network requests or file reads often does not require you to create threads yourself.
You reach for worker threads when:
- the work is CPU-heavy,
- it would block the event loop,
- and you want JavaScript to run in parallel on another thread.
For ordinary asynchronous I/O, async and evented APIs are still the normal answer.
Create a Worker Thread
The worker_threads module is the built-in way to do this.
When you run this file, the main thread starts a worker, the worker computes a result, and sends it back with postMessage.
Why Worker Threads Exist
JavaScript on the main thread shares one event loop. If you do expensive CPU work there, the whole process becomes unresponsive.
For example, a naive image transformation or large numeric loop can block:
- HTTP request handling,
- timers,
- and other asynchronous callbacks.
Moving that work to a worker thread isolates it from the main event loop.
A Better CPU-Bound Example
Here is a simple worker that computes a sum:
This kind of work is where worker threads actually help.
Message Passing and Shared Memory
By default, worker threads communicate with messages. That is the simplest and safest model:
- main thread sends data,
- worker does the work,
- worker sends back a result.
Node also supports shared memory through SharedArrayBuffer, but that is a more advanced design. For most applications, plain message passing is the right starting point.
Worker Threads Are Not Free
Creating workers has overhead:
- startup cost,
- memory cost,
- and serialization cost for messages.
That means you should not spawn a new worker for every tiny task. If you have lots of small CPU jobs, a worker pool is usually better than one worker per request.
Do Not Confuse Worker Threads With the libuv Thread Pool
Node already uses a background thread pool internally for some operations such as:
- filesystem work,
- DNS,
- crypto,
- and compression.
That internal pool is not the same as worker_threads. The libuv pool helps native and system tasks. Worker threads are for running JavaScript in parallel.
When to Use Processes Instead
Sometimes separate processes are better than threads:
- stronger isolation,
- separate memory spaces,
- and easier crash containment.
Node's cluster module and process-based architectures are still useful, but they solve a different problem from lightweight in-process worker threads.
Common Pitfalls
The biggest pitfall is creating worker threads for I/O-bound work that was already non-blocking. That adds complexity without solving the real problem.
Another mistake is spawning too many workers or creating a new worker for every tiny task. Worker startup and messaging overhead can outweigh the benefit.
Developers also often forget that the main value of worker threads is protecting the event loop from CPU-bound work, not making every Node program automatically faster.
Finally, do not confuse worker threads with the built-in libuv thread pool. They are different mechanisms with different jobs.
Summary
- Use
worker_threadswhen you need CPU-bound JavaScript to run in parallel. - Do not create threads for ordinary async I/O unless there is a specific reason.
- Workers communicate primarily through message passing.
- Worker creation has overhead, so use pooling for many small jobs.
- The event loop, the libuv thread pool, and worker threads are related but distinct parts of Node's concurrency story.

