Field-by-Field Breakdown of `0 * * * *`
| Position | Field Name | Allowed Values | Value in `0 * * * *` | Evaluation Meaning |
|---|---|---|---|---|
| 1 | Minute | 0 – 59 | 0 | 0 (At minute 0 of the hour) |
| 2 | Hour | 0 – 23 | * | * (Every hour: 00:00 through 23:00) |
| 3 | Day of Month | 1 – 31 | * | * (Every day of the month: 1-31) |
| 4 | Month | 1 – 12 | * | * (Every month: 1-12) |
| 5 | Day of Week | 0 – 6 (Sun-Sat) | * | * (Every day of the week: 0-6) |
The Critical Difference Between `0 * * * *` and `* * * * *`
A common mistake among junior sysadmins is writing `* 1 * * *` or `* * * * *` when intending an hourly schedule. An asterisk in the minute field means 'every minute', not 'once per hour'. Specifying `0 * * * *` locks execution strictly to the top of the hour: 01:00, 02:00, 03:00, and so on.
Linux systems also support the special string `@hourly`, which is functionally identical to `0 * * * *`. However, explicit numeric notation (`0 * * * *`) is preferred for portability across BSD, Solaris, and busybox environments.
Because thousands of automated server scripts default to `0 * * * *`, shared hosting platforms and public APIs experience massive CPU and network traffic spikes at minute :00. In production, staggering jobs to non-zero minutes (such as `17 * * * *` or `43 * * * *`) prevents resource contention.
Common Production Scenarios for `0 * * * *`
Hourly Database WAL & Log Rotation
Compresses hourly web server access logs or writes database transaction log snapshots to cold S3 storage.
/usr/sbin/logrotate /etc/logrotate.d/hourly-nginxCurrency Exchange Rate & Stock Ticker Sync
Queries external financial APIs (ECB, Forex) to cache updated exchange rates in memory for consumer pricing tables.
/usr/bin/node /opt/rates/sync-forex.jsExpired User Session Cleanup
Scans Redis or database tables to invalidate expired authentication tokens and prune stale cart reservations.
/usr/bin/php /var/www/artisan auth:prune-tokensProduction Gotchas When Running `0 * * * *`
- Minute Zero Contention: Scheduling heavy tasks at `0 * * * *` competes with system cron maintenance jobs. Choose an offset like `7 * * * *` to distribute load.
- Timezone Traps: Cron runs in the server's local system time unless an explicit `TZ` variable is declared at the top of the crontab file.
- Long-running Jobs: If an hourly job takes 65 minutes, the next run will spawn while the first is active unless isolated with locking.
Frequently Asked Questions About `0 * * * *`
What is the difference between `0 * * * *` and `* 1 * * *`?
`0 * * * *` runs once every hour at minute zero (24 times daily). `* 1 * * *` runs every single minute during 1:00 AM to 1:59 AM (60 times in one hour, and never during other hours).
Can I use `@hourly` instead of `0 * * * *`?
Yes, modern Linux distributions (Vixie Cron and Cronie) support the `@hourly` shortcut, which is an exact alias for `0 * * * *`.
How do I run a job every hour at minute 15 instead of minute 0?
Set the minute field to `15`: `15 * * * * /path/to/script.sh`. The job will trigger at 01:15, 02:15, 03:15, avoiding peak top-of-hour server contention.