BeeThreads
πThe best DX to threads in Nodejs π
Install / Use
/learn @samsantosb/BeeThreadsREADME
π bee-threads
<div align="center">β‘ THE BEST THREADS DX IN NODE.JS β‘
Parallel programming made simple. Zero boilerplate. Zero dependencies.
</div>Install
npm install bee-threads
import { bee, beeThreads } from 'bee-threads'
// Anything inside bee() runs on a separate thread
const result = await bee((x: number) => x * 2)(21) // 42
bee() - Simple Curried API
// No arguments
await bee(() => 42)()
// With arguments
await bee((a: number, b: number) => a + b)(10, 20) // 30
// With closures
const TAX = 0.2
await bee((price: number) => price * (1 + TAX))(100, { beeClosures: { TAX } }) // 120
Fluent API Methods
beeThreads.run() - Full Control
await beeThreads
.run((a: number, b: number) => a + b)
.usingParams(10, 20)
.execute() // 30
.setContext() - Inject Variables
const TAX = 0.2
await beeThreads
.run((price: number) => price * (1 + TAX))
.usingParams(100)
.setContext({ TAX })
.execute() // 120
.signal() - Cancellation
const controller = new AbortController()
const promise = beeThreads
.run(() => heavyComputation())
.signal(controller.signal)
.execute()
controller.abort() // Cancel anytime
.retry() - Auto-retry
await beeThreads
.run(() => fetchFromFlakyAPI())
.retry({ maxAttempts: 5, baseDelay: 100, backoffFactor: 2 })
.execute()
.priority() - Queue Priority
await beeThreads.run(() => processPayment()).priority('high').execute()
await beeThreads.run(() => generateReport()).priority('low').execute()
.transfer() - Zero-copy ArrayBuffer
const buffer = new Uint8Array(10_000_000)
await beeThreads
.run((buf: Uint8Array) => processImage(buf))
.usingParams(buffer)
.transfer([buffer.buffer])
.execute()
.reconstructBuffers() - Buffer Reconstruction
const buffer = await beeThreads
.run((img: Buffer) => require('sharp')(img).resize(100).toBuffer())
.usingParams(imageBuffer)
.reconstructBuffers()
.execute()
Buffer.isBuffer(buffer) // true
beeThreads.turbo() - Parallel Arrays
Process arrays across ALL CPU cores. Non-blocking (main thread stays free).
const numbers = [1, 2, 3, 4, 5, 6, 7, 8]
const squares = await beeThreads.turbo(numbers).map((x: number) => x * x)
const evens = await beeThreads.turbo(numbers).filter((x: number) => x % 2 === 0)
const sum = await beeThreads.turbo(numbers).reduce((a: number, b: number) => a + b, 0)
// Custom worker count
await beeThreads.turbo(numbers).setWorkers(8).map((x: number) => x * x)
// With context
const factor = 2.5
await beeThreads.turbo(data, { context: { factor } }).map((x: number) => x * factor)
Default workers:
os.cpus().length - 1(leaves one core for main thread)
beeThreads.worker() - File Workers
When you need require(), database connections, or external modules.
// workers/hash-password.js
const bcrypt = require('bcrypt')
module.exports = async function (password) {
return bcrypt.hash(password, 12)
}
// main.ts - Just use relative path, it works! β¨
const hash = await beeThreads.worker('./workers/hash-password.js')('secret123')
β Smart Path Resolution
Relative paths (./ or ../) are automatically resolved from your file's location, not from process.cwd(). No more __dirname boilerplate!
// β
Just works - resolved from YOUR file's directory
beeThreads.worker('./workers/task.js')
beeThreads.worker('../shared/worker.js')
// β
Absolute paths also work
beeThreads.worker('/app/workers/task.js')
TypeScript Workers
For TypeScript, point to the compiled .js file:
// src/workers/process.ts β compiled to dist/workers/process.js
// β
Point to compiled JS
beeThreads.worker('./workers/process.js') // if running from dist/
// β
Or use explicit path to dist
import { join } from 'path'
beeThreads.worker(join(__dirname, '../dist/workers/process.js'))
Worker File Format
// workers/my-worker.js
const db = require('./database')
// Option 1: Direct export (recommended)
module.exports = async function (data) {
return db.process(data)
}
// Option 2: Default export
module.exports.default = async function (data) {
return db.process(data)
}
worker().turbo() - File Workers + Parallel Arrays
Process large arrays with database access across multiple workers.
// workers/process-users.js
const db = require('../database')
module.exports = async function (users) {
return Promise.all(
users.map(async user => ({
...user,
score: user.value * 10,
data: await db.fetch(user.id),
}))
)
}
// main.ts - 10,000 users across 8 workers
const results = await beeThreads.worker('./workers/process-users.js').turbo(users, { workers: 8 })
Default workers:
os.cpus().length - 1
When to Use
| Need | Use |
| ------------------------------- | ------------------ |
| Pure computation (no I/O) | turbo() |
| Single DB call | worker() |
| Batch processing + DB/API | worker().turbo() |
| ETL pipelines | worker().turbo() |
| Data enrichment at scale | worker().turbo() |
Configuration
beeThreads.configure({
poolSize: 8,
minThreads: 2,
maxQueueSize: 1000,
workerIdleTimeout: 30000,
debugMode: true,
logger: console,
})
await beeThreads.warmup(4)
await beeThreads.shutdown()
Error Handling
import { TimeoutError, AbortError, QueueFullError, WorkerError } from 'bee-threads'
try {
await beeThreads.run(fn).execute()
} catch (err) {
if (err instanceof TimeoutError) { /* timeout */ }
if (err instanceof AbortError) { /* cancelled */ }
if (err instanceof WorkerError) { /* worker error */ }
}
// Safe mode - never throws
const result = await beeThreads.run(fn).safe().execute()
if (result.status === 'fulfilled') console.log(result.value)
When to Use
| Your Scenario | Best Choice | Why |
|---------------|-------------|-----|
| Arrays | turbo() | SharedArrayBuffer = zero-copy |
| Single heavy function | bee() | Keeps main thread free |
| Light function (x * 2) | Main thread | Overhead > benefit |
| Need require()/DB | worker() | Full Node.js access |
| Batch processing with full import features | worker().turbo() | Parallel + DB access |
| HTTP server | turbo() | Non-blocking for requests |
Limitations (Inline Functions)
When using bee(), beeThreads.run(), or turbo() (without worker()), data is transferred via Structured Clone Algorithm.
β What CAN be passed as parameters
| Type | Works |
|------|-------|
| Primitives (string, number, boolean, null, undefined, BigInt) | β
|
| Arrays, Objects (POJOs) | β
|
| Date, RegExp, Map, Set | β
|
| ArrayBuffer, TypedArrays (Uint8Array, Float64Array, etc.) | β
|
| Error (with custom properties) | β
|
| Nested objects | β
|
β What CANNOT be passed as parameters
| Type | Why |
|------|-----|
| Functions | Not cloneable (use setContext instead) |
| Symbols | Not cloneable |
| Class instances | Lose prototype and methods |
| WeakMap, WeakSet | Not cloneable |
| Circular references | Not supported |
| Streams | Not cloneable |
β οΈ Closures Must Be Explicit
Functions lose access to external variables when sent to workers:
// β FAILS - x doesn't exist in worker
const x = 10
await bee((a) => a + x)(5) // ReferenceError: x is not defined
// β
WORKS - pass x explicitly
const x = 10
await bee((a) => a + x)(5, { beeClosures: { x } }) // 15
// β FAILS - helper loses access to multiplier
const multiplier = 2
const helper = (n) => n * multiplier
await beeThreads.run((x) => helper(x))
.setContext({ helper }) // helper is stringified, loses closure!
.usingParams(5)
.execute()
// β
WORKS - pass all dependencies
await beeThreads.run((x) => helper(x))
.setContext({ helper, multiplier })
.usingParams(5)
.execute() // 10
Need
require(), database, or npm modules? UsebeeThreads.worker()instead.
Why bee-threads?
- Zero dependencies - Lightweight and secure
- Inline functions - No separate worker files
- Worker pool - Auto-managed, no cold-start
- Function caching - LRU cache, 300-500x faster
- Worker affinity - V8 JIT optimization
- Request coalescing - Deduplicates identical calls
- Turbo mode - Parallel array processing
- File workers - External files with
require()+ turbo - Full TypeScript - Complete type inference
MIT Β© Samuel Santos
Related Skills
node-connect
342.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Writing Hookify Rules
84.7kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
review-duplication
99.6kUse this skill during code reviews to proactively investigate the codebase for duplicated functionality, reinvented wheels, or failure to reuse existing project best practices and shared utilities.
