Skip to main content

@repo/queue

A type-safe, schema-driven queue abstraction for Node.js.

  • Job definitions as values
  • Payload types inferred from schemas
  • Queue-agnostic core with adapter-based backends
  • Separate client and worker concerns
  • Inspired by Laravel queues, built for TypeScript

Installation

npm install @repo/queue

Install a queue backend adapter as needed:

npm install pg-boss

Defining a Job

import { createJob } from "@repo/queue";
import { z } from "zod";

export const sendEmailsJob = createJob("send-emails", {
input: z.object({
email: z.string().email(),
subject: z.string(),
body: z.string(),
}),
handler: async ({ email, subject, body }, ctx) => {
// payload is fully typed
},
hooks: {
onError: (err, payload, ctx) => {},
onFailed: (err, payload, ctx) => {},
onSuccess: (result, payload, ctx) => {},
},
});
  • payload type is inferred from the schema
  • handler receives parsed/validated input
  • hooks are fully typed

Creating the Queue Runtime

import { createQueueRuntime } from "@repo/queue";
import { createPgBossAdapter } from "@repo/queue/adapters/pg-boss";
import { sendEmailsJob } from "./jobs/sendEmails.job";

export const queueRuntime = createQueueRuntime({
queues: [
{ name: "low", priority: 0 },
{ name: "high", priority: 10 },
],
adapter: createPgBossAdapter({
connectionString: process.env.DATABASE_URL,
}),
workers: [
{
job: sendEmailsJob,
concurrency: 10,
queues: ["low"],
},
],
});

Running Workers

Start listening to the workers in Svelte.

// hooks.server.ts 
queueRuntime.startWorkers();

Dispatching Jobs (Client)

// src/lib/queue/queueClient.server.ts
const queueClient = queueRuntime.createClient();
await queueClient.dispatch(
sendEmailsJob,
{ email, subject, body },
);
  • Dispatch is type-safe
  • Payload must match the job schema
  • Queue names are validated at compile time

There is a third argument you can pass for more context:

await queueClient.dispatch(
sendEmailsJob,
{ email, subject, body },
{ maxAttempts: 5, queue: "low" }
);

Adapters

The core is queue-agnostic. Backends are provided via adapters.

Currently supported:

  • pg-boss

Adapters are optional peer dependencies and only required if you use them.

Design Notes

  • Jobs are first-class values, not strings
  • Schemas define both runtime validation and TypeScript types
  • No decorators, no DI container, no global registry
  • Client and worker responsibilities are explicit