Quick answer
The cron expression for every 30 minutes is */30 * * * *. The */30 step in the minute field matches minutes 0 and 30, so the job runs on the hour and at half past: twice an hour, 48 times a day. Writing 0,30 * * * * gives exactly the same schedule, and 15,45 * * * * keeps the rhythm but moves it off the hour.
- Live next runs
- Any time zone
- Field-by-field breakdown
- Seven platform snippets
- Daylight saving aware
How to use this schedule
- 1Copy
*/30 * * * *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.
What does */30 * * * * mean?
*/30 keeps every thirtieth minute starting at 0, and the minute range only has room for two: 0 and 30. With so few values, the list form 0,30 is arguably clearer, and it makes the half-hour offset obvious too: 15,45 or 10,40 keep the 30-minute spacing without firing on the hour.
Three look-alikes catch people out, so it is worth comparing them side by side:
| Expression | What it does |
|---|---|
*/30 * * * * | :00 and :30 of every hour |
0,30 * * * * | The same, written as a list |
30 * * * * | Once an hour, at :30 only |
*/30 * * * * * | Every 30 seconds (6-field syntax) |
The last one is the 6-field format used by Spring and node-cron, where the first field is seconds (Quartz writes it with ? in a day field). See every 30 seconds for that schedule.
When does a 30-minute schedule make sense?
Half-hourly suits data that changes steadily but not urgently: syncing a product catalog, refreshing an internal dashboard, collecting files dropped on an SFTP server, or pulling metrics from a provider that only updates a few times an hour. At 48 runs a day it is gentle on rate-limited APIs.
A neat property: because the rhythm is every half hour, it stays aligned with the local clock even in zones with half-hour offsets, such as India at UTC+05:30. A server on UTC running */30 * * * * still fires on the hour and at half past in Mumbai.
The interval only works this cleanly because 30 divides 60. Steps that don't, such as */40, restart every hour and give uneven gaps (:00, :40, then :00 again 20 minutes later). For a true 40- or 90-minute interval you need several lines or a scheduler with fixed intervals. If you want fewer runs instead, every hour is the next step up.
What does each field in */30 * * * * mean?
| Field | Value | Allowed | Meaning |
|---|---|---|---|
| Minute | */30 | 0–59 | every 30 minutes: :00 and :30 |
| 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: On the hour and at half past (:00 and :30), every hour of every day.
How do I adjust */30 * * * * to my own schedule?
Small edits to */30 * * * * cover most real-world needs:
| Expression | What it does |
|---|---|
0,30 * * * * | The same schedule written as a list |
15,45 * * * * | Every 30 minutes at quarter past and quarter to |
*/30 8-18 * * * | Every 30 minutes from 08:00 to 18:30 |
*/30 * * * 1-5 | Every 30 minutes on weekdays only |
0 * * * * | Every hour, on the hour |
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 15 minutes · Every hour · Every 30 seconds · Every 10 minutes
Browse all schedules in the cron schedule library.
How do I run */30 * * * * in crontab, GitHub Actions, Kubernetes and the cloud?
| Platform | Write it as | Time zone |
|---|---|---|
| Linux crontab | */30 * * * * | Server's time zone; CRON_TZ= in cronie |
| GitHub Actions | - cron: "*/30 * * * *" | UTC by default; add timezone: (IANA name) |
| Kubernetes CronJob | schedule: "*/30 * * * *" | Set timeZone: (1.27+) |
| Cloudflare Workers | */30 * * * * | UTC only; numbers weekdays from 1 = Sunday, so use names |
| Vercel Cron Jobs | */30 * * * * | UTC only; more than once a day needs Pro (Hobby: once a day) |
| AWS EventBridge Scheduler | cron(*/30 * * * ? *) | Takes a time zone; legacy scheduled rules are UTC only |
| systemd timer | OnCalendar=*-*-* *:00,30:00 | Add a zone after the time, e.g. Europe/London |
In a crontab (crontab -e), the full line looks like this:
*/30 * * * * /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 */30 * * * *?
30 * * * *(no slash) is a common slip: it runs once an hour at :30, not every 30 minutes.- Don't mix up the 5-field
*/30 * * * *with the 6-field*/30 * * * * *used by Spring and node-cron, which runs every 30 seconds. Count the fields before you deploy. - Steps don't carry over the hour, so
*/40 * * * *isn't every 40 minutes: it runs at :00 and :40, leaving a 20-minute gap. 30 works because it divides 60 evenly. - Long exports or backups scheduled every half hour can overlap themselves on slow days. Use
flock -n /tmp/job.lock your-command. - 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.