threadsx
Workers as simple as a function call.
One transparent API over web workers and Node worker threads:
spawn() a worker, call its functions, await the results.
A maintained, modernized fork of
threads.js.
$npm install threadsx
This is the whole idea
Expose functions from a worker, call them from the main thread like any other async function. Same code in the browser and in Node.
import { spawn, Thread, Worker } from "threadsx"
const auth = await spawn(new Worker("./workers/auth"))
const hashed = await auth.hashPassword("Super secret", "1234")
console.log("Hashed password:", hashed)
await Thread.terminate(auth)import sha256 from "js-sha256"
import { expose } from "threadsx/worker"
expose({
hashPassword(password, salt) {
return sha256(password + salt)
}
})import { Pool, spawn, Worker } from "threadsx"
const pool = Pool(() => spawn(new Worker("./workers/crunch")), 4)
for (const file of files) {
pool.queue(crunch => crunch(file))
}
await pool.completed()
await pool.terminate()import { spawn, Worker } from "threadsx"
const counter = await spawn(new Worker("./workers/counter"))
// Worker functions can return observables:
counter.values().subscribe(count => {
console.log("Progress:", count)
})What to expect
No message-passing boilerplate, no bundler plugins, no stale types.
Transparent async calls
Worker functions look like local async functions. Errors reject the promise with the real error, not a cryptic event.
Thread pools built in
Pool() spawns workers, queues tasks, limits concurrency, and reports events. Terminate it and every worker goes with it.
Observables & streaming
Return an observable from a worker to stream values. Subscribe on the main thread; unsubscribing cancels the job in the worker.
Shared workers across tabs
spawnShared() gives every tab one worker instance — native SharedWorker where available, a BroadcastChannel fallback elsewhere — with broadcast() events to all tabs.
Zero-copy transfers
Wrap ArrayBuffers in Transfer() to move them between threads instead of copying. Non-cloneable values fail with a clear ThreadCloneError.
Bundler-native
Works out of the box with webpack 5, Vite, esbuild and rollup via new Worker(new URL(…, import.meta.url)). Real ESM and CommonJS builds, no plugin required.
Actively maintained
TypeScript-first with self-contained types, leak-audited worker lifecycle, and a test suite that runs on Linux, macOS, Windows and real Chromium in CI.