Schedules
Static cron on tasks, and dynamic schedules at runtime.
OpenQueue supports two kinds of schedules: static cron declared on the task, and dynamic schedules created at runtime.
Static cron
Declare cron on the task and the worker registers it on boot. Each tick
runs with input derived from the task schema defaults. Schema-less cron tasks
run with {}:
export const weeklyDigest = task({
id: 'weekly-digest',
schema: z.object({}).default({}),
cron: '0 9 * * MON',
run: async () => sendDigests(),
});If a cron task has a schema with required fields and no defaults, worker boot fails because OpenQueue cannot invent scheduled input.
Dynamic schedules
Create, list, and delete schedules programmatically — per user, per tenant, or from an admin UI — without redeploying:
await weeklyDigest.schedules.create({
cron: '0 8 * * *',
input: {},
deduplicationKey: `digest:${customerId}`,
});
const schedules = await weeklyDigest.schedules.list();
await weeklyDigest.schedules.delete(scheduleId);Dynamic schedules require a storage adapter (see Persistence) so they survive restarts.
In Workbench
The Schedules view shows every schedule — static and dynamic — with its cron expression in plain English, the next run time, and the last run's outcome and duration. Pause, resume, or edit cron expressions from the UI.
Cron expressions are validated with assertCron before they're accepted, so
a typo fails at create time, not silently at 3am.