npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@robiscoding/orpc-worker-pool

v0.1.1

Published

oRPC plugin for offloading CPU-intensive procedures to a managed Node.js worker thread pool

Readme

oRPC Worker Pool

An oRPC plugin that offloads CPU-intensive procedures to a managed pool of Node.js worker threads, keeping your main thread responsive.

Use Cases

Node.js runs JavaScript on a single thread. Any procedure that does heavy computation — image processing, data parsing, cryptography, report generation — will block the event loop and stall all other requests while it runs.

orpc-worker-pool solves this by routing marked procedures to a pool of worker threads that run in parallel. The main thread stays free to handle incoming requests while workers churn through the expensive work.

Good candidates for offloading:

  • Image/video processing and transformation
  • Large file parsing (CSV, XML, JSON)
  • Cryptographic operations (hashing, encryption)
  • Report generation or PDF rendering
  • Any tight loop or CPU-bound algorithm

Requirements

  • Node.js >= 22
  • @orpc/server ^1.13.0 (peer dependency)

Installation

npm install @robiscoding/orpc-worker-pool
# or
pnpm add @robiscoding/orpc-worker-pool

Getting Started

1. Mark procedures for offloading

Add meta: { offload: true } to any procedure you want to run in a worker thread:

// router.ts
import { os } from '@orpc/server'

export const router = {
  hashPassword: os
    .meta({ offload: true }) // set offload to true to run in worker thread
    .input(z.object({ password: z.string() }))
    .handler(async ({ input }) => {
      // This runs in a worker thread
      return expensiveHash(input.password)
    }),

  greet: os
    .input(z.object({ name: z.string() }))
    .handler(async ({ input }) => {
      // No offload meta — runs on the main thread as normal
      return `Hello, ${input.name}`
    }),
}

2. Register the plugin

Pass a WorkerOffloadPlugin instance to your oRPC server. The routerPath must point to the compiled JS file that exports your router. Worker threads load it fresh each time.

// server.ts
import { createServer } from '@orpc/server'
import { WorkerOffloadPlugin } from '@robiscoding/orpc-worker-pool'
import { router } from './router'
import { fileURLToPath } from 'url'
import path from 'path'

const plugin = new WorkerOffloadPlugin({
  routerPath: path.join(__dirname, 'router.js'), // path to the compiled router
  pool: 4,          // number of worker threads (default: 4)
  queueLimit: 100,  // max queued tasks before rejecting (default: 100); useful for adding backpressure
})

const handler = createServer(router, {
  plugins: [plugin],
})

// Shut down workers gracefully on exit
process.on('SIGTERM', () => plugin.terminate())

Usage Guide

Configuration Options

| Option | Type | Default | Description | |---|---|---|---| | routerPath | string | required | Absolute path to the compiled JS file exporting your router | | pool | number | 4 | Number of worker threads to spawn | | queueLimit | number | 100 | Max number of tasks that can be queued when all workers are busy |

Error Handling

Errors thrown inside a worker are serialized across the thread boundary and wrapped in WorkerOffloadPluginError. Because postMessage uses structured clone, custom error properties are preserved via the .defined and .code fields.

  • If the procedure threw an ORPCError, .defined is true and .code holds the error code.
  • Otherwise .defined is false and only the message is preserved.
import { WorkerOffloadPluginError } from '@robiscoding/orpc-worker-pool'

try {
  await client.hashPassword({ password: '...' })
} catch (err) {
  if (err instanceof WorkerOffloadPluginError) {
    if (err.defined) {
      // A known ORPCError — err.code has the oRPC error code
      console.error('Procedure error:', err.code, err.message)
    } else {
      // An unexpected error from the worker
      console.error('Worker error:', err.message)
    }
  }
}

Graceful Shutdown

Call plugin.terminate() before your process exits to drain in-flight tasks and shut down worker threads cleanly:

process.on('SIGTERM', async () => {
  await plugin.terminate()
  process.exit(0)
})

Any tasks still queued or in-flight when terminate() is called are immediately rejected with a WorkerOffloadPluginError.

License

MIT