Skip to content

@hourly

Every Hour at Minute 0. @hourly runs at the top of every hour (minute 0) — identical to 0 * * * *. See the expansion, offset-minute patterns to avoid load spikes, Quartz/AWS equivalents, and simulate live.

Where the @hourly macro is supported and its equivalents
DialectExpression
Unix cron / Cloudflare@hourly
Quartz / Spring0 0 * * * ?
AWS EventBridge0 * * * ? *

Next 5 executions of @hourly (UTC)

Next 5 execution times in UTC for @hourly
#Execution time (UTC)
12026-11-02 19:00 UTC
22026-11-02 20:00 UTC
32026-11-02 21:00 UTC
42026-11-02 22:00 UTC
52026-11-02 23:00 UTC
Edit & simulate @hourly in your timezone

@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.

All cron shortcut macros