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

isolated-workers

v0.2.0

Published

Type-safe worker process library for Node.js with full TypeScript inference.

Readme

isolated-workers

Type-safe worker process library for Node.js with full TypeScript inference.

npm version License: MIT

Features

  • Type-safe messaging - Full TypeScript inference for payloads and responses
  • Process isolation - True process boundaries for CPU-intensive tasks
  • Multiple drivers - Child processes (default) or worker threads
  • Cross-platform - Unix domain sockets and Windows named pipes
  • Middleware support - Logging, validation, timing, and custom pipelines
  • Timeout configuration - Per-message-type and global timeout settings
  • Zero dependencies - No runtime dependencies

Installation

npm install isolated-workers
# or
pnpm add isolated-workers
# or
yarn add isolated-workers

Requirements: Node.js 20.10+ and TypeScript 5.0+

Quick Start

1. Define Your Message Contract

/**
 * Shared message definitions for the basic-ping example
 *
 * This file is imported by both the host and worker to ensure
 * type safety and avoid duplication.
 */

import { DefineMessages } from 'isolated-workers';

/**
 * Message types for the ping-pong example
 */
export type Messages = DefineMessages<{
  ping: {
    payload: { message: string };
    result: { message: string };
  };
}>;

2. Create the Worker

/**
 * Basic Ping-Pong Worker - Worker (Server) Side
 *
 * This script runs as the worker process and responds to ping messages.
 */

import { startWorkerServer, Handlers } from 'isolated-workers';
import type { Messages } from './messages.js';

// Define handlers for incoming messages with proper typing
const handlers: Handlers<Messages> = {
  ping: ({ message }) => {
    console.log(`Worker received: ${message}`);
    return { message: 'pong' };
  },
};

// Start the worker server
async function main() {
  console.log('Worker starting...');

  const server = await startWorkerServer(handlers);

  console.log('Worker ready and waiting for messages');

  // Keep the process alive until explicitly stopped
  process.on('SIGTERM', async () => {
    console.log('Worker received SIGTERM, shutting down...');
    await server.stop();
    process.exit(0);
  });
}

main().catch((err) => {
  console.error('Worker error:', err);
  process.exit(1);
});

3. Spawn and Communicate

/**
 * Basic Ping-Pong Worker - Host (Client) Side
 *
 * This script spawns a worker process and sends a ping message,
 * then receives and prints the pong response.
 */

import { createWorker } from 'isolated-workers';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import type { Messages } from './messages.js';

// Get the directory of this file for spawning the worker
const __dirname = dirname(fileURLToPath(import.meta.url));

async function main() {
  console.log('Spawning worker process...');

  // Create a worker that runs worker.ts
  const worker = await createWorker<Messages>({
    script: join(__dirname, 'worker.ts'),
    timeout: 10000,
  });

  console.log(`Worker spawned with PID: ${worker.pid}`);

  try {
    // Send a ping message
    console.log('Sending ping message...');
    const result = await worker.send('ping', { message: 'ping' });

    console.log('Received response:', result);
  } catch (err) {
    console.error('Error:', (err as Error).message);
  } finally {
    // Always close the worker
    await worker.close();
    console.log('Worker closed successfully');
  }
}

main();

Advanced Example: Image Processing

For a more complete example with per-operation timeouts and batch processing:

Message Definitions

export type Messages = DefineMessages<{
  // Process an image and return metadata
  processImage: {
    payload: {
      imagePath: string;
      options: { grayscale: boolean; quality: number };
    };
    result: {
      width: number;
      height: number;
      format: string;
      size: number;
    };
  };

  // Batch process multiple images
  batchProcess: {
    payload: {
      paths: string[];
      options: { grayscale: boolean; quality: number };
    };
    result: {
      successful: number;
      failed: number;
      results: Array<{ path: string; success: boolean }>;
    };
  };

  // Get current worker status
  getStatus: {
    payload: Record<string, never>;
    result: {
      active: boolean;
      processedCount: number;
    };
  };
}>;

Creating the Worker with Timeouts

// Spawn the worker with per-operation timeouts
  const worker = await createWorker<Messages>({
    script: join(__dirname, 'worker.ts'),
    // Configure timeouts for different operations
    timeout: {
      WORKER_STARTUP: 5000, // 5s to start
      processImage: 30000, // 30s per image
      batchProcess: 300000, // 5min for batch
    },
  });

Sending Messages

// Process a single image
    const metadata = await worker.send('processImage', {
      imagePath: './photo.jpg',
      options: { grayscale: true, quality: 85 },
    });
    console.log('Image metadata:', metadata);

Drivers

isolated-workers supports two execution strategies:

Child Process (Default)

True process isolation with separate memory space:

const worker = await createWorker<Messages>({
    script: './worker.js',
    // Uses child_process driver by default
  });

Worker Threads

In-process workers with shared memory support:

const worker = await createWorker<Messages, typeof WorkerThreadsDriver>({
    script: './worker.js',
    driver: WorkerThreadsDriver,
  });

See Worker Threads Driver for a complete example.

Timeout Configuration

Configure timeouts globally or per-message-type:

// Define timeout configuration
  const timeoutConfig: TimeoutConfig<Messages> = {
    // Worker lifecycle timeouts
    WORKER_STARTUP: 5000, // 5 seconds to start
    SERVER_CONNECT: 5000, // 5 seconds for server to accept connection

    // Default message timeout
    WORKER_MESSAGE: 3000, // 3 seconds default for messages

    // Per-message-type timeouts (override WORKER_MESSAGE)
    quickPing: 1000, // 1 second for quick operations
    slowProcess: 10000, // 10 seconds for slow operations
  };
const worker = await createWorker<Messages>({
    script: join(__dirname, 'worker.ts'),
    timeout: timeoutConfig,
  });

See Timeout Configuration for more details.

Middleware

Add logging, validation, or custom processing:

/**
 * Logging middleware - logs all messages with direction
 */
const loggingMiddleware: Middleware<Messages> = (message, direction) => {
  const arrow = direction === 'outgoing' ? '>>>' : '<<<';
  console.log(
    `[${direction.toUpperCase()}] ${arrow} ${message.type}`,
    message.payload
  );
  return message;
};
// Create worker with middleware pipeline
  // Middleware is applied in order: logging -> timing
  const worker = await createWorker<Messages>({
    script: join(__dirname, 'worker.ts'),
    timeout: 10000,
    middleware: [loggingMiddleware, timingMiddleware],
  });

See Middleware Pipeline for the complete middleware example.

Error Handling

Errors thrown in workers are automatically propagated to the host:

/**
 * Error Handling Example - Worker (Server) Side
 *
 * Demonstrates error throwing and propagation.
 */

import { startWorkerServer, Handlers } from 'isolated-workers';
import type { Messages } from './messages.js';

// Define handlers for incoming messages with proper typing
const handlers: Handlers<Messages> = {
  divide: ({ a, b }) => {
    console.log(`Worker: dividing ${a} / ${b}`);

    if (b === 0) {
      throw new Error('Division by zero');
    }

    return { result: a / b };
  },
};

async function main() {
  console.log('Worker: starting error-handling demo worker');

  await startWorkerServer(handlers);

  console.log('Worker: ready');

  process.on('SIGTERM', () => {
    console.log('Worker: shutting down');
    process.exit(0);
  });
}

main().catch((err) => {
  console.error('Worker error:', err);
  process.exit(1);
});
/**
 * Error Handling Example - Host (Client) Side
 *
 * Demonstrates error propagation from worker to host.
 */

import { createWorker } from 'isolated-workers';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import type { Messages } from './messages.js';

const __dirname = dirname(fileURLToPath(import.meta.url));

async function main() {
  console.log('=== Error Handling Example ===\n');

  const worker = await createWorker<Messages>({
    script: join(__dirname, 'worker.ts'),
    timeout: 10000,
  });

  console.log(`Worker spawned with PID: ${worker.pid}\n`);

  // Test 1: Successful division
  console.log('Test 1: 10 / 2');
  try {
    const result = await worker.send('divide', { a: 10, b: 2 });
    console.log('Result:', result.result, '\n');
  } catch (err) {
    console.error('Unexpected error:', (err as Error).message, '\n');
  }

  // Test 2: Division by zero (should error)
  console.log('Test 2: 10 / 0 (should error)');
  try {
    await worker.send('divide', { a: 10, b: 0 });
    console.log('ERROR: Should have thrown!\n');
  } catch (err) {
    console.log('Caught expected error:', (err as Error).message, '\n');
  }

  // Test 3: Cleanup
  console.log('Test 3: Cleanup');
  await worker.close();
  console.log('Worker closed successfully\n');

  console.log('=== All tests passed ===');
}

main().catch((err) => {
  console.error('Host error:', err);
  process.exit(1);
});

See Error Handling for more patterns.

When to Use isolated-workers

Good fit:

  • CPU-intensive tasks (image processing, data parsing, crypto)
  • Plugin systems requiring isolation
  • Sandboxed code execution
  • Long-running background jobs

Better alternatives:

  • Simple async I/O → use Promises directly
  • Shared memory requirements → use worker_threads directly
  • Very high-frequency messaging → consider batching or SharedArrayBuffer

Documentation

Full documentation and examples at craigory.dev/isolated-workers

API Overview

Host Side

// Create a worker
const worker = await createWorker<Messages>(options);

// Send messages
const result = await worker.send('messageType', payload);

// Check status
worker.isActive;     // true if worker can accept messages
worker.isConnected;  // true if connection established

// Graceful shutdown
await worker.close();

Worker Side

// Start the server with handlers
const server = await startWorkerServer<Messages>(handlers, options);

// Server automatically handles:
// - Message deserialization
// - Handler dispatch
// - Response serialization
// - Error propagation
// - Graceful shutdown (SIGTERM)

Type Helpers

import type {
  DefineMessages, // Extract result type
  Handlers, // Define message contracts
  MessageOf, // Extract message type
  PayloadOf, // Extract payload type
  ResultOf, // Extract result type
} from 'isolated-workers';

Examples

License

MIT © Craigory Coppola