Crontab Every Hour: The Right Syntax and What Cron Won't
August 19, 2026


The Crontab Expression to Run a Job Every Hour
The correct crontab expression to run a job every hour is:
0 * * * * /path/to/script.sh
Cron reads five fields, in order: minute, hour, day of month, month, day of week. In 0 * * * *, the 0 means "at minute zero," and the four asterisks mean "every hour, every day, every month, every day of the week." This cron every hour syntax fires the job once, at the top of every hour, 24 times a day — at 00:00, 01:00, 02:00, and so on.
That leading 0 is the difference between a job that runs on a predictable schedule and one that runs far more often than intended — the confusion covered next. For a refresher on every field and symbol cron supports, the Crontab Cheat Sheet: Syntax, Symbols & Schedules breaks it down field by field.
0 * * * * vs * * * * * vs @hourly
These three expressions get confused constantly, but only one reliably means "every hour."
0 * * * *— runs once per hour, at minute 0. This is the correct hourly cron expression.* * * * *— runs every single minute, 1,440 times a day. A bare asterisk in the minute field means "every minute," not "every hour" — a common mistake that quietly floods logs, queues, or downstream APIs with far more traffic than intended.*/1 * * * *— functionally identical to* * * * *. The*/1step syntax means "every 1 unit starting from the base," which for minutes is still every single minute. It isn't safer or clearer than a plain asterisk — it's the same schedule written differently.
Then there's @hourly, a nonstandard shorthand supported by Vixie cron and some other implementations. It expands to 0 * * * *. It's shorter to type and easy to read, but it isn't part of the POSIX crontab standard, and not every cron daemon, container base image, or scheduler UI recognizes it. If you're deploying across mixed environments — Alpine containers, BSD systems, older enterprise Linux — stick with the explicit 0 * * * * so the schedule behaves identically everywhere. Tools like crontab.guru are a fast way to sanity-check any expression before you commit it.
Running Every 2, 3, 6, or 12 Hours Instead
Once you understand that the hour field controls which hours a job fires on, adapting the base expression to run every N hours is a matter of using cron's step syntax (*/N) or an explicit hour range.
- Every 2 hours:
0 */2 * * *— fires at 00:00, 02:00, 04:00, and so on. - Every 3 hours:
0 */3 * * *— fires at 00:00, 03:00, 06:00, etc. - Every 6 hours:
0 */6 * * *— fires four times a day, at 00:00, 06:00, 12:00, 18:00. - Every 12 hours:
0 */12 * * *— fires twice a day, at 00:00 and 12:00.
For business-hours-only schedules, combine an hour range with a step or list. To run hourly between 9am and 5pm on weekdays: 0 9-17 * * 1-5. That restricts execution to the 9-through-17 hour window, Monday through Friday, while still firing once per hour within it.
For a four-hour cadence, or a broader library of copy-paste intervals, the Crontab Cheatsheet: Copy-Paste Schedules & Syntax Table covers more variations side by side. If you manage scheduling through Jenkins rather than raw crontab, note that Jenkins' H modifier (e.g., H */2 * * *) intentionally randomizes the exact minute within the range — which leads directly into the next problem.
Two Pitfalls That Hit Hourly Jobs Specifically
The thundering herd at the top of the hour. Every job scheduled with a minute value of 0 fires at exactly the same second across every server, container, and cron daemon that runs it. On a single machine that's harmless. Across a fleet, or against a shared database, API, or cache, dozens or hundreds of jobs hitting the same target simultaneously creates a real load spike — connection pool exhaustion, rate-limit errors, or CPU contention that only appears once an hour and is maddening to diagnose because it's intermittent by design. The fix is simple: offset the minute field. Changing 0 * * * * to 7 * * * * or 23 * * * * spreads load away from the crowd without changing how often the job runs. Jenkins' H modifier automates this offset by hashing the job name into a consistent-but-distributed minute.
Daylight saving time. If your system clock is set to local time in a region that observes DST, the hour field can betray you twice a year. When clocks spring forward and 2am is skipped entirely, an hourly job scheduled for that hour simply doesn't fire — a cron DST skip. When clocks fall back and 1am happens twice, some cron implementations run the matching job twice in the same real-world hour, duplicating emails, reports, or billing runs. The most reliable mitigation is to pin the cron daemon or container to UTC rather than local time; UTC has no DST transitions, so an hourly schedule stays exactly one hour apart, year-round. If local time is unavoidable, at minimum build idempotency into jobs that run near the 1am–3am window so a duplicate or missed run doesn't cause damage.
Your Schedule Is Correct — But Is It Still Running?
Getting the expression right solves half the problem. Cron has no built-in mechanism to tell you when a job stops firing — no alert, no dashboard, no notification. A dependency gets removed during a server migration, a script starts throwing an error before it completes, disk fills up, a container image changes and the crontab file doesn't come with it — and the job goes quiet. Because nothing crashes visibly, a cron job not running can go unnoticed for weeks. The schedule was never wrong; the job just stopped executing, silently.
This is the reliability gap syntax alone can't close. Confirming an hourly job is still alive means checking that it actually ran, not just that it was scheduled to. The How to Check Cron: The 4-Layer Verification Checklist walks through the layers worth verifying manually — but manual checks don't scale once you have more than a couple of scheduled jobs to watch.
That's the problem Cronevra solves directly. Point your hourly job at a Cronevra check-in URL, and if an expected ping doesn't arrive within your grace window, you get alerted — instead of finding out three weeks later that a critical hourly sync silently died. Setting up hourly cron monitoring takes minutes: add one line to your existing script, and every future run reports in. See Pricing to find a plan that fits your job count, and stop finding out about cron job silently failing from an angry customer instead of an alert.
Frequently Asked Questions
What is the crontab syntax to run a job every hour?
The correct expression is 0 * * * *, which fires once at minute zero of every hour, every day. The five fields represent minute, hour, day of month, month, and day of week — the leading 0 pins execution to the top of the hour rather than every minute.
What does @hourly mean in crontab?
@hourly is a nonstandard shorthand that expands to 0 * * * * on systems that support it, such as Vixie cron. It isn't part of the POSIX standard, so some cron implementations, container images, and schedulers won't recognize it — using the explicit 0 * * * * is safer for portability.
Does */1 * * * * do the same thing as * * * * *?
Yes, both run every single minute. */1 isn't a safer or more explicit version of "every hour"; it's step syntax that reduces to "every unit," which for the minute field means every minute.
How do I run a cron job every 2 or 3 hours instead of every hour?
Use step values in the hour field: 0 */2 * * * runs every 2 hours, and 0 */3 * * * runs every 3 hours. The same pattern extends to 0 */6 * * * for every 6 hours and 0 */12 * * * for every 12 hours.
Why does my hourly cron job run twice or get skipped around daylight saving time?
If the cron daemon uses local time in a DST-observing region, the "spring forward" transition skips an hour entirely, causing a scheduled run to be missed, while "fall back" repeats an hour, sometimes triggering a duplicate run. Pinning the system or container to UTC removes DST transitions entirely and keeps hourly spacing consistent year-round.
How do I know if my hourly cron job silently stopped running?
You need active monitoring, since cron itself has no built-in alerting when a job fails to execute. Services like Cronevra let a job "check in" on each successful run, and alert you the moment an expected check-in doesn't arrive — surfacing failures within minutes instead of weeks.