For your AI agents, emails, payments, and more

A simple background
jobs framework.

Start as one TypeScript process with SQLite. Grow into a Station Network backed by PostgreSQL, MySQL, or Redis when you need more capacity. Retries, cron scheduling, workflows, long-running services, and a fleet dashboard are included.

// 00

A love letter to
everything you automate.

Your AI agentsthat run on a schedule, retry on failure, and report back when they're done.
Your emailsthat go out in the background without blocking your request handler.
Your paymentsthat process reliably with retries, even when a provider hiccups.
Your reportsthat generate overnight and land in an inbox by morning.
Your webhooksthat fan out to downstream services without you babysitting the queue.
01Simple codeDefine a signal in TypeScript. Schema in, handler out. That's it.
02Simple deploymentSQLite when one process is enough. Shared adapters and execution stations when it is not.
03Simple monitoringEvery run recorded. Station dashboard included. One command to start.
// 01

What you get.

Everything you need for production background jobs. Nothing you don't.

Scheduling & triggers

Intervals plus five-field cron in an IANA timezone. Preview future occurrences, trigger on demand, and claim each fleet occurrence exactly once.

Run history

Every execution recorded with input, output, errors, timing, and attempt count. Query through the adapter or browse with Station's monitoring dashboard.

Automatic retries

Per-signal retry count with exponential backoff. .retries(3) gives 4 total attempts. Failed jobs re-enqueue automatically without intervention.

Type-safe inputs

Zod schemas validate every trigger payload before it enters the queue. TypeScript infers handler argument types from the schema. Invalid data never reaches your handler.

Concurrency limits

Bound a signal per Station and across the whole network. Add placement labels so GPU, regional, or specialized work only reaches eligible workers.

Workflow DAGs

Chain signals into directed acyclic graphs with broadcasts. Fan-out to parallel nodes, fan-in with data aggregation, conditional execution via guard functions.

Long-running beacons

Supervise long-lived processes — servers, pollers, and clients — with restart policies, exponential backoff, heartbeat stall detection, and graceful shutdown.

Station Networks

Put Headquarters in front of a fleet. Route stateless work, drain workers, deduplicate schedules, supervise beacons, and inspect everything from one dashboard.

// 02

Define it in TypeScript.
Run it anywhere.

A signal is a background job definition — input schema, handler function, execution constraints. Define them in your codebase. The runner auto-discovers signal files, handles scheduling, retries, timeouts, and concurrency. StationKit adds configuration only when you want the dashboard or a multi-process network.

View documentation →
love-letter.ts
import { signal, z } from "station-signal" export const loveLetter = signal("loveLetter")  .input(z.object({ to: z.string() }))  .every("1d")  .retries(2)   // Step 1: compose the letter  .step("compose", async (input) => {    const letter = await ai.generate(      "To all the jobs I love..."    )    return { to: input.to, letter }  })   // Step 2: send it  .step("send", async (prev) => {    await mailer.send({ to: prev.to, body: prev.letter })    return prev  })   // Step 3: tip a dollar  .step("tip", async (prev) => {    await wallet.send(prev.to, 1.00)  })   .build()
// 03

One Station when you're small.
A whole network when you're not.

Headquarters gives clients one API while execution stations advertise capacity, labels, and definitions. Atomic claims choose one owner for every run and schedule occurrence; leases recover work when a worker disappears. Drain nodes and watch the entire fleet from the dashboard.

Station Network dashboard with Headquarters and two execution stations
LIVE FLEET INVENTORY · CAPACITY · DRAINING · HEARTBEATS
// 04

Why another
background jobs library?

Existing solutions work. They also come with trade-offs Station doesn't.

Self-hosted queues
Bull, BullMQ, Agenda
  • Requires Redis or MongoDB
  • Docker and ops overhead
  • Complex configuration
  • Full control over execution
Managed services
Trigger.dev, Inngest
  • Hosted infrastructure
  • Additional cloud bill
  • Data on third-party servers
  • Vendor-specific APIs
This library
Station
  • SQLite by default; shared adapters when you scale
  • One process or a fleet of execution stations
  • Runs on your servers with no hosted control plane
  • One API and dashboard across the network
  • Full TypeScript with Zod validation
  • Same reliability: retries, timeouts, concurrency
// Get started

Five minutes to your first signal.

Install the runtime and StationKit, define a signal, then start Station. SQLite is enough for the first process.

pnpm add station-signal station-kit
Read the guide