The expression
*/30 * * * *
Runs at minute 0 and minute 30 of every hour, every day: twice an hour, 48 times a day.
| Field | Value | Meaning |
|---|---|---|
| Minute | */30 |
every 30th minute, starting at 0 |
| Hour | * |
every hour |
| Day of month | * |
every day |
| Month | * |
every month |
| Day of week | * |
every day of the week |
*/30 is the same as 0,30. Many people find 0,30 * * * * easier to read; cron treats both identically.
Variants
| Schedule | Expression |
|---|---|
| Every 30 minutes at :15 and :45 | 15,45 * * * * |
| Every 30 minutes on weekdays | */30 * * * 1-5 |
| Every 30 minutes from 9:00 to 17:30 | */30 9-17 * * * |
| Every 15 minutes | */15 * * * * |
| Every hour | 0 * * * * |
| Every 90 minutes | two lines: 0 0-21/3 * * * and 30 1-22/3 * * * |
Every 90 minutes can't be one expression, because a minute step never crosses into the next hour. The two lines above give 00:00, 01:30, 03:00, 04:30 … 22:30 and back to 00:00: an even 90-minute gap, 16 runs a day.
Where to write it
- crontab (Linux, macOS):
*/30 * * * * /usr/local/bin/digest.shincrontab -e, in the server's time zone. - GitHub Actions:
on: schedule: - cron: '*/30 * * * *'. UTC only; the 5-minute minimum isn't an issue here, but scheduled runs can be delayed under load, and GitHub disables schedules in public repositories with no activity for 60 days. - Kubernetes CronJob:
schedule: "*/30 * * * *", withtimeZone:when you restrict hours or days, andconcurrencyPolicy: Forbidfor long jobs. - AWS EventBridge:
cron(0/30 * * * ? *)(six fields,?in day of week), orrate(30 minutes), which is anchored to when the rule was created rather than to :00 and :30.
Common mistakes
30 * * * *runs once an hour, at half past, not every 30 minutes.*/45is not every 45 minutes. It runs at :00 and :45, so the gaps alternate between 45 and 15 minutes. Steps only divide one hour.- Half-hour time zones. If your users are in India (UTC+5:30), "on the hour" locally is :30 in UTC, so the two runs swap meaning on a UTC scheduler.
- No lock. Use
flock -n /tmp/digest.lock commandif a run might take more than 30 minutes.
Paste any expression into the Cron Expression Parser to see it in words and its next run times.