--- title: 'Schedule' description: 'Fires the workflow on a recurring cron schedule.' --- # Schedule Runs the workflow every time the cron expression matches. OneHazel evaluates schedules once per minute via a `pg_cron` job, so the minimum granularity is one minute. ## When to use - Hourly/daily/weekly rollups. - Periodic health pings to external services. - Batch reconciliation that doesn't need real-time events. - Anything you'd historically put in a cron tab. ## Configuration | Field | Required | What it does | |---|---|---| | `cronExpression` | Yes | Five-field cron: `minute hour day month weekday`. Seconds and year are not supported. | | `timezone` | No | Which timezone to evaluate the cron in. Defaults to UTC. | ## Cron cheat sheet | Expression | Runs | |---|---| | `* * * * *` | Every minute | | `0 * * * *` | Top of every hour | | `0 9 * * *` | 9:00 AM daily | | `0 0 * * 0` | Midnight every Sunday | | `*/15 * * * *` | Every 15 minutes | | `0 9 * * 1-5` | 9:00 AM weekdays only | | `0 0 1 * *` | Midnight on the 1st of each month | The timezone setting affects when the cron fires, not the events themselves. Pick the timezone your business operates in so "9 AM daily" makes sense to humans. ## What it outputs The trigger produces a payload containing the scheduled tick time: ``` { trigger: { data: { scheduledAt: "2026-04-18T09:00:00.000Z", cron: "0 9 * * *" } } } ``` Downstream nodes can reference `{{trigger.data.scheduledAt}}` if they need the exact tick time (useful for reports and audit logs). ## Gotchas - **Clock drift**: the scheduler ticks every ~60 seconds, so expect ±1 minute of jitter on fire times. Don't rely on exact-to-the-second timing. - **Missed ticks**: if the scheduler is down when your cron fires, the tick is missed — OneHazel does **not** replay missed schedules. - **Overlapping runs**: if your workflow takes longer than one minute to finish and your cron fires every minute, you will have overlapping executions. Wrap long-running work in idempotency guards if this matters.