0 * * * * runs a job once an hour, on the hour. Most cron implementations also accept @hourly as a shortcut for exactly this.
Why the zero matters
The first field is the minute. 0 pins it to minute zero, so the job runs at 10:00, 11:00, 12:00. A common mistake is * * * * * or * */1 * * *: both run every minute, because the minute field is still *.
When it fires
Checked at 09:58 UTC, the next five runs are:
10:00 11:00 12:00 13:00 14:00
To run at a different minute past each hour, put it in the first field: 17 * * * * runs at 10:17, 11:17 and so on. Picking a minute other than 0 spreads load away from the top of the hour, when many jobs start at once.
The same schedule elsewhere
- GitHub Actions:
cron: '0 * * * *'. Runs at the top of the hour are the most likely to be delayed, so another minute is often better. - Kubernetes CronJob:
schedule: "0 * * * *", or"@hourly". - AWS EventBridge:
rate(1 hour), orcron(0 * * * ? *). - systemd timer:
OnCalendar=hourly. - Spring
@Scheduled:0 0 * * * *.