@hourly in production
What @hourly actually does
@hourly expands to 0 * * * *: minute 0, every hour, every day. It is the canonical "top of the hour" schedule — the one log rotation, hourly metrics flushes, and cheap health checks have used since the BSD days. Like all Vixie macros it is case-insensitive and accepted by Debian, Ubuntu, RHEL, and macOS cron; Quartz, AWS EventBridge, and Kubernetes CronJobs want the expanded five fields instead.
Because the minute field is 0, an @hourly job fires at 00:00, 01:00, 02:00 — exactly aligned with the wall clock. That is the right default for anything a human correlates with "hourly" logs. It is also the most crowded minute of the hour: logrotate, cert checkers, and half the internet's monitoring run at :00 too.
The top-of-hour stampede
If an @hourly job calls a shared resource — an API with rate limits, a database that every server also polls at :00 — you have joined the thundering herd. The standard fix is an offset minute: 17 * * * * runs at :17 every hour, same cadence, none of the collision. The offset form is also what you want for health checks whose latency graphs should not spike in lockstep with the rest of the fleet.
The systemd equivalent is OnCalendar=hourly on a .timer unit (which, like cron, fires at the top of the hour), and Celery beat expresses it as crontab(minute=0). Kubernetes has no macro form: schedule: "0 * * * *" in the CronJob spec. The expression is the contract everywhere; only the wrapper changes — and you can paste @hourly straight into the simulator above to watch the next fires in your timezone.
Common questions
What is the cron expression for every hour?
0 * * * *, which is exactly what @hourly expands to. If you need a different minute, replace the leading 0 — 30 * * * * runs at half past every hour.
Is there a difference between @hourly and 0 * * * *?
None at runtime. @hourly is a readability macro that the cron daemon expands to 0 * * * * before scheduling. Prefer the explicit form when the expression will be parsed by tools that don't implement macros.
How do I run hourly but not at minute 0?
There is no offset macro — set the minute explicitly: 17 * * * * fires at :17 of every hour. Offsetting is the common cure for top-of-hour load spikes on shared APIs and databases.
Does @hourly work in Quartz or AWS EventBridge?
No. Quartz needs 0 0 * * * ? (seconds first, '?' in one day field) and AWS EventBridge needs 0 * * * ? * with the trailing year field. Both platforms accept only explicit fields.