Quick answer
The 6-field cron expression for every 30 seconds is */30 * * * * *, where the first field is seconds, so it fires at second 0 and second 30 of every minute. Spring and node-cron accept it directly; Quartz needs a question mark in one day field, as */30 * * * * ?. Standard crontab cannot: its smallest unit is one minute, so you run two lines, one of them prefixed with sleep 30, or use a systemd timer.
- 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.
Why can't standard cron run every 30 seconds?
Classic crontab has five fields and the first one is the minute. The daemon wakes once a minute, checks which entries match the current minute and starts them. There is no seconds field, so nothing finer than one minute can be expressed.
*/30 * * * * * comes from the 6-field dialect used by Spring's @Scheduled(cron = …) and node-cron. They add a seconds field at the front, and */30 in that slot means seconds 0 and 30. Spring requires all six fields and node-cron makes seconds optional. Quartz also puts seconds first but rejects this exact string: one day field must be ?, so there it is */30 * * * * ?. Count the fields before you deploy: the same characters mean very different things in the two dialects.
| Expression | Fields | Runs |
|---|---|---|
*/30 * * * * * | 6, seconds first | Every 30 seconds |
*/30 * * * * | 5, minute first | Every 30 minutes |
If you paste the 6-field version into crontab -e, nothing warns you. Cron reads the first five fields as an every-30-minutes schedule and hands the final * to the shell as the command, which expands to the file names in the home directory.
How do I run a job every 30 seconds on Linux?
You have three good options, depending on how exact the timing needs to be:
- Two crontab lines. Both fire every minute; the second waits 30 seconds first.
- A systemd timer with
OnCalendar=*:*:0/30andAccuracySec=1s. The default accuracy is one minute, which would blur a 30-second rhythm, so lowering it matters. - A long-running worker that loops and sleeps. Best when the work is really continuous, such as polling a queue.
* * * * * /path/to/job
* * * * * sleep 30; /path/to/jobThe sleep trick is approximate: sleep 30 starts counting when cron launches the line, a moment after the minute begins, so the second run lands slightly after :30. Over a day that is 2,880 runs, and if any run takes longer than 30 seconds the two lines overlap. Guard both with the same lock file. If you only need near-real-time rather than exactly 30 seconds, every minute is simpler and fully portable.
What does each field in */30 * * * * * mean?
| Field | Value | Allowed | Meaning |
|---|---|---|---|
| Second | */30 | 0–59 | every 30 seconds: :00 and :30 |
| Minute | * | 0–59 | every minute |
| 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 second 0 and second 30 of every minute, using the 6-field syntax with a leading seconds field.
How do I adjust */30 * * * * * to my own schedule?
Small edits to */30 * * * * * cover most real-world needs:
| Expression | What it does |
|---|---|
*/15 * * * * * | Every 15 seconds, in 6-field syntax |
0,30 * * * * * | The same schedule written as a list: second 0 and second 30 |
15,45 * * * * * | Every 30 seconds, offset to :15 and :45 of each minute |
*/30 * 9-17 * * 1-5 | Every 30 seconds during business hours, Monday to Friday (6-field) |
* * * * * | Every minute, the closest standard crontab gets |
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 minute · Every 2 minutes · Every 5 minutes · Every 30 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 | Two lines with sleep (see below) | Server's time zone; CRON_TZ= in cronie |
| GitHub Actions | Not supported (1-minute minimum) | UTC by default; add timezone: (IANA name). Runs at most every 5 minutes |
| Kubernetes CronJob | Not supported (1-minute minimum) | Set timeZone: (1.27+) |
| Cloudflare Workers | Not supported (1-minute minimum) | UTC only; numbers weekdays from 1 = Sunday, so use names |
| Vercel Cron Jobs | Not supported (1-minute minimum) | UTC only; more than once a day needs Pro (Hobby: once a day) |
| AWS EventBridge Scheduler | Not supported (1-minute minimum) | Takes a time zone; legacy scheduled rules are UTC only |
| systemd timer | OnCalendar=*-*-* *:*:00,30 | Add a zone after the time, e.g. Europe/London |
In a crontab (crontab -e), the full line looks like this:
* * * * * /path/to/job.sh
* * * * * sleep 30; /path/to/job.shThe 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 * * * * *?
- Pasting
*/30 * * * * *into a regular crontab doesn't fail loudly: cron reads the first five fields as every 30 minutes and treats the last*as the command. - The
sleep 30trick is two independent jobs. If a run takes longer than 30 seconds they overlap, so put both lines behind the same lock:flock -n /tmp/job.lock /path/to/job. - systemd timers default to
AccuracySec=1min, which lets runs drift anywhere within a minute. SetAccuracySec=1sor the 30-second rhythm disappears. - GitHub Actions, Kubernetes CronJobs, Cloudflare Cron Triggers and Vercel have no seconds field, and AWS EventBridge stops at one minute. For sub-minute work there, run a long-lived worker that sleeps 30 seconds between iterations.
- At 2,880 runs a day, a log line per run adds up quickly. Log failures only, or rotate the log file.
- 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.