Background jobs, done right

Run reliable background jobs without the infra headache.

Relay is a queue and scheduler you call like a function. Durable retries, observability, and zero servers to babysit — add it to your app in a few lines.

Open SDKGenerous free tierSOC 2
bash
$ npm i @relay/sdk

# enqueue a job in one line
await relay.run("send-email", { to: user.email });

Works with any Node, Bun, or edge runtime.

Platform

Everything a job queue should have been.

Durable, observable, and pleasant to use.

Durable retries

Exponential backoff, dead-letter queues, and replay — built in.

Schedules & crons

Human-readable schedules.

Live observability

Every run, traced.

Typed end to end

Your job payloads are type-checked from enqueue to handler — no stringly-typed surprises.

Rate limiting

Per-queue concurrency control.

The whole API

A typed function is the entire interface.

Define a handler, enqueue from anywhere — payloads are type-checked end to end.

jobs/send-welcome.ts
import { defineJob } from "@relay/sdk";

export const sendWelcome = defineJob({
  name: "send-welcome",
  retries: 5,
  run: async ({ userId }: { userId: string }) => {
    const user = await db.users.find(userId);
    await email.send(user.email, "welcome");
  },
});

// elsewhere — fully typed, no stringly-typed payloads
await sendWelcome.enqueue({ userId: user.id });

Same code runs on Node, Bun, and the edge.

Drops into the stack you already run

Next.jsBunPostgresRedisAWSCloudflare
Reliability, measured

The numbers a background queue lives or dies on.

99.98%Job delivery — the run happenstrailing 90 days, all queues
212msMedian enqueue-to-start latencyp50; p95 is 340ms
0Runs lost to a Relay outageenqueues buffer and drain on recovery
4.1BJobs run for teams on Relay
Pricing

Pay for throughput, not seats.

Start free, no card. A run is one job attempt that starts — retries don't multiply your bill.

Free

$0/mo

For side projects and prototypes.

  • 10k runs / mo
  • 3-day retention
  • Community support
Popular

Pro

$49/mo

For apps in production.

  • 1M runs / mo
  • 30-day retention
  • Concurrency controls
  • Email support

Scale

Custom

High volume + compliance.

  • Unlimited runs
  • SSO & SOC 2
  • Dedicated support
FAQ

The questions an engineer asks before adding a dependency.

The honest answers — pricing, self-host, migration, and what happens at the limit.

Can I self-host, or am I locked into your cloud?

Both. The SDK and worker are open-source (Apache-2.0) and run against your own Postgres and Redis — no phone-home. The hosted plans add the dashboard, retention, and on-call; you can start self-hosted and move later, or never.

Why priced on runs instead of per seat?

Because your whole team benefits from one queue, but your bill should track what you actually push through it. A run is one job attempt that starts; retries of the same job don't multiply your count. No per-developer tax.

How do I migrate from BullMQ, Sidekiq, or a homegrown cron?

Point your existing handlers at defineJob and enqueue through the SDK — the shape is deliberately familiar. Run both queues in parallel during cutover; Relay never touches the old one. Most teams migrate one queue a day, not all at once.

Is delivery at-least-once or exactly-once?

At-least-once, like every honest queue — a handler can run twice if a worker dies mid-run. Make handlers idempotent (each job carries a stable key you can dedupe on) and you get exactly-once behavior without us pretending the network is reliable.

What happens when I hit the free tier's 10k runs?

Enqueues keep succeeding — nothing drops on the floor. Overflow jobs queue and we email you to upgrade; they run as soon as you do. We'd rather you notice a bill than lose a job.

Ship background jobs you can trust.

Add Relay in a few lines and watch your queue actually behave.

Free forever for small projects · no card required · Apache-2.0 SDK