Skip to main content

Getting Started

End-to-end setup: define a job, create a runtime, start workers, dispatch work.

1. Define a Job

// src/lib/jobs/sendEmails.job.ts
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 from the schema
},
hooks: {
onError: (err, payload, ctx) => {},
onFailed: (err, payload, ctx) => {},
onSuccess: (result, payload, ctx) => {},
},
});

2. Create the Runtime

// src/lib/queue/runtime.server.ts
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"],
},
],
});

3. Start Workers

Call startWorkers() once at server startup. In SvelteKit, use hooks.server.ts:

// hooks.server.ts
import { queueRuntime } from "$lib/queue/runtime.server";

queueRuntime.startWorkers();

4. Dispatch Jobs

Create a client and dispatch type-safe payloads:

// src/lib/queue/queueClient.server.ts
import { queueRuntime } from "./runtime.server";

const queueClient = queueRuntime.createClient();
await queueClient.dispatch(sendEmailsJob, {
email: "user@example.com",
subject: "Welcome",
body: "Hello!",
});

Dispatch accepts an optional third argument for advanced options:

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