Node.jsWorker ThreadsPerformanceMultithreading

Node.js Worker Threads: Multithreading is Easy Now

S
Systems Engineer
Featured Guide 24 min read

Don't Block the Event Loop.

The golden rule of Node.js. But what if you have to calculate a hash, resize an image, or parse a massive JSON file?

In the past, you crashed. Today, you offload it to a Worker Thread.

02. Processes vs Threads

Child Process (fork)

Entire new V8 instance. Requires huge memory overhead. Slow startup.

Worker Thread

Shares the same process memory. Lightweight. Fast message passing via ArrayBuffers.

Deep Dive: Atomics & SharedArrayBuffer

True shared memory is possible! By passing a SharedArrayBuffer to a worker, both the main thread and the worker can read/write to the same memory address instantly.
Use Atomics to prevent race conditions.

03. Easy Pattern (bree / piscina)

Don't use the raw worker_threads API unless you are building a library. Use a pool manager like Piscina.

// main.js
const
Piscina = require('piscina');
const
imgWorker = new Piscina({'{'} filename: './resize.js' {'}'});

// This runs in background! Main thread free!
await imgWorker.run({'{'} file: 'avatar.png' {'}'});

04. The Senior Engineer's Take

Node is not Java.

Just because you can use threads doesn't mean you should make everything multithreaded. The Event Loop is still faster for I/O (DB queries, network requests).

Only use threads for CPU-bound tasks.

Interactive Playground

import React, { useState } from 'react';

// 🧵 Thread Visualizer

export default function ThreadsDemo() {
    const [mode, setMode] = useState('single'); // single | multi
    const [tasks, setTasks] = useState([]);
    
    // Create tasks
    const addTask = () => {
        const id = Math.random();
        setTasks(prev => [...prev, { id, progress: 0, status: 'pending' }]);
        
        // Simulation
        if (mode === 'single') {
            // Sequential processing (simulate blocking)
            // In real app we can't easily block specific UI parts here, so we simulate queue delay
             setTimeout(() => processTask(id), tasks.length * 1000 + 100);
        } else {
            // Parallel immediately
            setTimeout(() => processTask(id), 100);
        }
    };
    
    const processTask = (id) => {
        // Find task and animate it
        let p = 0;
        const interval = setInterval(() => {
            p += 10;
            setTasks(prev => prev.map(t => t.id === id ? { ...t, progress: p, status: 'running' } : t));
            
            if (p >= 100) {
                clearInterval(interval);
                setTasks(prev => prev.map(t => t.id === id ? { ...t, progress: 100, status: 'done' } : t));
            }
        }, 200);
    };

    return (
        <div className="bg-slate-50 dark:bg-slate-950 p-8 rounded-3xl border border-slate-200 dark:border-slate-800 shadow-xl">
             <div className="flex justify-between items-center mb-10">
                <h3 className="text-2xl font-black text-gray-900 dark:text-white flex items-center gap-3">
                    <span className="text-yellow-500">🧵</span> Task Scheduler
                </h3>
                <div className="flex bg-slate-200 dark:bg-slate-900 p-1 rounded-xl">
                    <button 
                        onClick={() => { setMode('single'); setTasks([]); }}
                        className={`px-6 py-2 rounded-lg font-bold text-sm transition-all ${mode === 'single' ? 'bg-white dark:bg-slate-800 shadow text-red-500' : 'text-slate-500'}`}
                    >
                        Single Thread
                    </button>
                    <button 
                        onClick={() => { setMode('multi'); setTasks([]); }}
                        className={`px-6 py-2 rounded-lg font-bold text-sm transition-all ${mode === 'multi' ? 'bg-white dark:bg-slate-800 shadow text-green-500' : 'text-slate-500'}`}
                    >
                        Worker Pool
                    </button>
                </div>
            </div>

            <div className="flex gap-4 mb-8">
                 <button 
                    onClick={addTask}
                    className="flex-1 py-4 bg-slate-900 text-white rounded-xl font-bold shadow-lg active:scale-95 transition-transform flex justify-center items-center gap-2"
                >
                    <span></span> Spawn CPU Task (Hash)
                </button>
            </div>

            <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
                
                {/* Main Thread Lane */}
                <div className="border border-slate-300 dark:border-slate-700 rounded-xl p-4 bg-white dark:bg-black/20 min-h-[300px]">
                    <div className="flex items-center gap-2 mb-4 font-bold text-gray-500 uppercase text-xs">
                         <span>⚙️</span> Main Event Loop
                    </div>
                    
                    {tasks.filter(t => t.status !== 'done').map(t => (
                        <div key={t.id} className="mb-2">
                             {mode === 'single' ? (
                                 <div className={`p-3 rounded-lg text-xs font-bold border ${t.status === 'running' ? 'bg-red-500 text-white border-red-600 animate-pulse' : 'bg-gray-100 dark:bg-slate-800 text-gray-400 border-dashed'}`}>
                                     {t.status === 'running' ? '🔥 BLOCKING CPU 🔥' : 'Queued (Waiting)...'}
                                     <div className="h-1 bg-black/20 mt-2 rounded-full overflow-hidden">
                                         <div className="h-full bg-white" style={{ width: `${t.progress}%` }}></div>
                                     </div>
                                 </div>
                             ) : (
                                 <div className="p-3 rounded-lg text-xs font-bold border bg-green-50 text-green-700 dark:bg-green-900/20 dark:text-green-400 border-green-200">
                                     ✨ Delegated to Worker
                                 </div>
                             )}
                        </div>
                    ))}
                    
                     {mode === 'single' && tasks.some(t => t.status === 'running') && (
                        <div className="mt-4 p-2 bg-red-100 text-red-600 text-xs rounded border border-red-200 flex items-center gap-2">
                            <span>⚠️</span> UI is Frozen!
                        </div>
                    )}
                </div>

                {/* Worker Pool Visualizer */}
                <div className="col-span-2 border border-slate-300 dark:border-slate-700 rounded-xl p-4 bg-slate-100 dark:bg-slate-900/50 min-h-[300px] relative">
                     <div className="flex items-center gap-2 mb-4 font-bold text-gray-500 uppercase text-xs">
                        <span>📚</span> Thread Pool (4 Threads)
                    </div>

                    {mode === 'single' ? (
                        <div className="absolute inset-0 flex items-center justify-center text-gray-400 text-sm font-mono">
                            Pool Idle (All work on Main)
                        </div>
                    ) : (
                        <div className="grid grid-cols-2 gap-4">
                             {tasks.filter(t => t.status !== 'done').map(t => (
                                <div key={t.id} className="p-4 bg-white dark:bg-slate-800 rounded-xl shadow-sm border border-slate-200 dark:border-slate-700">
                                     <div className="flex justify-between items-center mb-2">
                                         <span className="text-xs font-bold text-gray-500">Worker Thread</span>
                                         <span className="text-xs text-green-500 font-bold">{t.progress}%</span>
                                     </div>
                                     <div className="h-2 bg-gray-100 rounded-full overflow-hidden">
                                         <div className="h-full bg-green-500 transition-all duration-300" style={{ width: `${t.progress}%` }}></div>
                                     </div>
                                </div>
                             ))}
                        </div>
                    )}
                </div>

            </div>
        </div>
    );
}