Quick answer
The cron expression for every hour is 0 * * * *. The 0 in the minute field pins the run to the top of the hour, and the asterisk in the hour field allows all 24 hours, so the job runs at 00:00, 01:00 and so on through 23:00. The @hourly macro means exactly the same thing in crontab and Kubernetes.
- Live next runs
- Any time zone
- Field-by-field breakdown
- Seven platform snippets
- Daylight saving aware
How to use this schedule
- 1Copy
0 * * * *with the Copy expression button. - 2Check Next runs in your time zone to confirm it fires when you expect, including around daylight saving changes.
- 3Pick your platform under Use it on your platform and copy the ready-made crontab line, workflow, manifest or timer.
- 4Need a different time or day? Click Customize to open it in the cron expression generator and change any field.
Why is 0 * * * * hourly and * * * * * not?
An hourly schedule needs one fixed minute. Cron matches every field independently, so an asterisk in the minute field matches all 60 minutes of every hour. That is why * * * * * runs 1,440 times a day and 0 * * * * runs 24.
| Expression | Runs |
|---|---|
0 * * * * | At :00 of every hour, 24 times a day |
@hourly | The same, as a macro |
0 */1 * * * | The same, with a redundant step |
* * * * * | Every minute, 1,440 times a day |
* 0 * * * | Every minute from 00:00 to 00:59 |
The minute can be any value from 0 to 59. 17 * * * * is just as hourly as 0 * * * *; it simply fires at 00:17, 01:17 and so on.
Which minute should an hourly job use?
The top of the hour is the busiest minute on most systems, because 0 * * * * and @hourly are what everyone types first. Picking another minute is free and often helps:
- Spread load. A fleet of servers calling the same API at :00 creates a spike; give each job its own minute.
- Respect dependencies. If an upstream export finishes around :05, schedule the consumer at
10 * * * *. - Let the hour close. A job that reports on "the previous hour" should start a few minutes after it ends, e.g.
5 * * * *, so records written at :59 are included.
Need it only during the working day? See every hour during business hours. If hourly is more often than you need, every 2 hours or every 6 hours keep the same top-of-the-hour shape with fewer runs.
What does each field in 0 * * * * mean?
| Field | Value | Allowed | Meaning |
|---|---|---|---|
| Minute | 0 | 0–59 | at minute 0 (on the hour) |
| Hour | * | 0–23 | every hour |
| Day of month | * | 1–31 | every day of the month |
| Month | * | 1–12, JAN–DEC | every month |
| Day of week | * | 0–7 (0 and 7 are Sunday), SUN–SAT | every day of the week |
Read together: At minute 0 of every hour (00:00, 01:00 … 23:00), every day.
How do I adjust 0 * * * * to my own schedule?
Small edits to 0 * * * * cover most real-world needs:
| Expression | What it does |
|---|---|
17 * * * * | Every hour at 17 minutes past, away from the top-of-the-hour rush |
0 9-17 * * * | Every hour from 09:00 to 17:00 |
0 * * * 1-5 | Every hour on weekdays only |
30 * * * * | Every hour at half past |
0 */2 * * * | Every 2 hours |
Need something else? Click Customize at the top of the page to open this schedule in the cron expression generator and change any field.
Related schedules: Every 30 minutes · Every 2 hours · Every 3 hours · Business hours (every hour)
Browse all schedules in the cron schedule library.
How do I run 0 * * * * in crontab, GitHub Actions, Kubernetes and the cloud?
| Platform | Write it as | Time zone |
|---|---|---|
| Linux crontab | 0 * * * * | Server's time zone; CRON_TZ= in cronie |
| GitHub Actions | - cron: "0 * * * *" | UTC by default; add timezone: (IANA name) |
| Kubernetes CronJob | schedule: "0 * * * *" | Set timeZone: (1.27+) |
| Cloudflare Workers | 0 * * * * | UTC only; numbers weekdays from 1 = Sunday, so use names |
| Vercel Cron Jobs | 0 * * * * | UTC only; more than once a day needs Pro (Hobby: once a day) |
| AWS EventBridge Scheduler | cron(0 * * * ? *) | Takes a time zone; legacy scheduled rules are UTC only |
| systemd timer | OnCalendar=*-*-* *:00:00 | Add a zone after the time, e.g. Europe/London |
In a crontab (crontab -e), the full line looks like this:
0 * * * * /path/to/job.sh >> /var/log/job.log 2>&1The live panel at the top of the page builds complete, copy-ready files for each platform (workflow, CronJob manifest, wrangler.toml, vercel.json, AWS CLI and systemd units) and can shift the schedule to UTC for platforms that need it.
What can go wrong with 0 * * * *?
- Writing
* * * * *or* 0 * * *instead of0 * * * *is the classic hourly mistake: the first runs every minute, the second every minute between 00:00 and 00:59. - In a local time zone, the spring-forward day has only 23 hours to run in, and cronie runs an hourly job in both copies of the repeated hour when clocks fall back. Schedule in UTC if you need exactly 24 runs every day.
- An hourly job that sometimes takes more than an hour will overlap its next run. Put
flock -n /tmp/job.lockin front of the command. - Anything that processes the previous hour should start a few minutes after the hour, e.g.
5 * * * *, so late records from :59 are included. - In a zone with daylight saving time, a schedule with
*in the minute or hour field follows the wall clock: the spring-forward night loses an hour of runs and the fall-back night repeats one. Servers on UTC never see this.
Frequently asked questions
Last updated by the Playxoft engineering team.