Schedules
Standard cron, evaluated in UTC, fired independently of our API.
View as MarkdownA backup's schedule is a cron expression. It is validated when you save it, and a backup
that is not manual cannot become active without one.
Schedules are evaluated in UTC. There is no per-backup timezone today, so 0 2 * * *
means 02:00 UTC, not 02:00 where you are. Convert before you write it: a team in New York
wanting 02:00 local writes 0 7 * * * in winter and 0 6 * * * in summer, and has to
choose which of the two matters more.
Syntax
Standard five-field cron.
┌───────── minute 0-59
│ ┌─────── hour 0-23
│ │ ┌───── day of month 1-31
│ │ │ ┌─── month 1-12 or JAN-DEC
│ │ │ │ ┌─ day of week 0-6 or SUN-SAT
│ │ │ │ │
* * * * *| Expression | Fires |
|---|---|
0 2 * * * | 02:00 every day |
0 */6 * * * | Every six hours, on the hour |
30 3 * * 1-5 | 03:30 on weekdays |
0 3 * * 0 | 03:00 on Sundays |
0 4 1 * * | 04:00 on the first of the month |
0 5 1 1,4,7,10 * | 05:00 on the first day of each quarter |
15 1 * * MON | 01:15 on Mondays |
Named months and weekdays (JAN, MON) are accepted and are case-insensitive.
Shorthand
| Alias | Same as |
|---|---|
@hourly | 0 * * * * |
@daily | 0 0 * * * |
@weekly | 0 0 * * 0 |
@monthly | 0 0 1 * * |
@yearly, @annually | 0 0 1 1 * |
@15minutes, @30minutes | */15 * * * *, 0,30 * * * * |
Prefer the explicit form for anything running less than daily. @daily fires at midnight
UTC, which is the busiest minute of the day across every workspace we have.
Spread your schedules. 0 2 * * * on eleven backups means eleven dumps starting at the same
second, competing for the same worker, the same disk and the same source. Stagger them:
0 2, 20 2, 40 2.
Choosing a cadence
The question is not "how often can it run" but "how much work am I willing to redo".
| If losing this much work is acceptable | Schedule |
|---|---|
| A day | 0 2 * * * |
| Six hours | 0 */6 * * * |
| An hour | 0 * * * * |
Two constraints push the other way:
- A run must finish before the next one is due. A dump that takes seven hours cannot be on a six-hour schedule.
- Every run costs. Each one is billed for computation and for the storage it occupies, and each one is an artifact that retention has to sweep. See Pricing.
Overruns
If a run is still going when the next fire is due, the scheduled fire is skipped. Runs do not stack.
A backup that consistently skips is a backup whose schedule is wrong, and the fix is a longer interval rather than more concurrency. Two dumps of the same database at once is rarely what anyone wants.
A manual trigger is the exception: it always runs, even if a run is already in flight. That is deliberate, because "run it now" is usually said by someone who knows what they are doing and needs it regardless. Be aware of it when triggering a backup whose scheduled run may still be going.
Triggering outside the schedule
sctl backup trigger $BACKUP_ID
sctl run list --backup $BACKUP_IDA triggered run is an ordinary run in every other respect: same pipeline, same artifact, same retention, same billing. It does not shift the schedule, consume the next slot, or reset anything. The next scheduled fire happens exactly when it would have.
Trigger a backup after any change to it. A schedule you have never watched fire is a hypothesis.
Pausing
Pausing suspends the schedule without touching the definition or its artifacts.
sctl backup pause $BACKUP_ID
sctl backup resume $BACKUP_ID| Pause | Delete | |
|---|---|---|
| Schedule | Suspended | Gone |
| Definition | Kept | Gone |
| Artifacts | Kept, and still swept by retention | Blocks the delete while any remain |
| Reversible | Yes | No |
Pause during a migration, a maintenance window, or while a source is being rebuilt. Runs are not queued up while paused: resuming starts from the next scheduled fire rather than replaying what was missed.
A manual backup has no schedule and therefore cannot be paused.
Independence
Schedules fire from the orchestration layer directly, not from our API. A backup fires on time even if the API is having a bad day, which is the point of scheduling it there rather than in a cron loop of ours.
For a local backup the fire lands on your worker's queue. If the worker is offline, the run
queues rather than being skipped, and executes when the worker returns. See
lifecycle.