Every 30 Seconds
*/30 * * * * * 0/30 * * * * ? Runs every 30 seconds (twice a minute). Requires a seconds-aware dialect — Spring or Quartz — because standard Unix cron is minute-precision only.
Use in your stack
# Two entries, offset by half a minute. At 30s this is the one
# interval where the crontab workaround stays genuinely tidy.
* * * * * flock -n /tmp/heartbeat.lock /usr/local/bin/heartbeat.sh
* * * * * sleep 30; flock -n /tmp/heartbeat.lock /usr/local/bin/heartbeat.sh
# Or a systemd timer — /etc/systemd/system/heartbeat.timer
# AccuracySec is required; the 1min default would coalesce both
# firings into a single per-minute run.
# [Timer]
# OnCalendar=*-*-* *:*:00/30
# AccuracySec=1s
{
"schedule": {
"cron": "0/30 * * * * ?",
"timezone": "UTC"
}
}
// 6-field: second minute hour day-of-month month day-of-week
@Scheduled(cron = "*/30 * * * * *")
public void everyThirtySeconds() {
// ...
}
// Simpler for pure intervals:
@Scheduled(fixedRate = 30000) // milliseconds
public void everyThirtySecondsFixedRate() {
// ...
}
Next runs
Pick a timezone to see when this expression fires next.
- 012026-08-19T14:17:30.000Z
- 022026-08-19T14:18:00.000Z
- 032026-08-19T14:18:30.000Z
- 042026-08-19T14:19:00.000Z
- 052026-08-19T14:19:30.000Z
- 062026-08-19T14:20:00.000Z
- 072026-08-19T14:20:30.000Z
- 082026-08-19T14:21:00.000Z
- 092026-08-19T14:21:30.000Z
- 102026-08-19T14:22:00.000Z
Variations
Common use cases
- Polling a queue or inbox twice a minute for lower latency than a 1-minute cron.
- Refreshing a cache or health status on a 30-second heartbeat.
- Emitting a keep-alive or liveness ping to a monitoring system.
- Flushing a metrics buffer downstream at a steady twice-per-minute rate.
Gotchas
- **Unix crontab cannot do this in one line.** The 5-field format has no seconds field; its minimum interval is one minute. Two entries — one plain, one offset with `sleep 30` — is the standard workaround, and at this interval it's the tidiest it ever gets. See the Linux tab above.
- **If you reach for a systemd timer, set `AccuracySec=1s`.** It defaults to **1 minute**, so `OnCalendar=*-*-* *:*:00/30` alone lets systemd coalesce both firings into one per minute. The unit looks right and runs half as often as intended — this is the most common reason a sub-minute timer quietly misbehaves.
- In Spring, `*/30 * * * * *` is the 6-field form (seconds first) — not Unix's `*/30 * * * *`, which means every 30 *minutes*.
- In Quartz, use `0/30 * * * * ?` — `0/30` in the seconds field means "from second 0, every 30 seconds" (so it fires at :00 and :30 of each minute), and `?` fills the unused day-of-week field.
- `@Scheduled(fixedRate = 30000)` (Spring) or `tokio::time::interval` (Rust) expresses the same interval without a cron parser and is often the simpler choice.
- If a run can take longer than 30 seconds, prefer `fixedDelay` or an in-flight guard so runs don't overlap.
Unix cron is minute-precision — five fields, no seconds — so “every 30 seconds” can’t be written as a single crontab line.
On Linux, without changing schedulers
Thirty seconds is the friendliest case for the sleep-offset workaround: just two entries, one offset by half a minute (full block in the Linux tab above). Every tighter interval multiplies the line count — 20s needs three, 15s four, 10s six, 5s twelve.
It’s still approximate. sleep 30 starts when cron forks the job rather than at the top of the minute, so the second copy drifts under load; flock -n stops a slow run from stacking on the next one.
A systemd timer is the better answer if the box has systemd:
[Timer]
OnCalendar=*-*-* *:*:00/30
AccuracySec=1s
AccuracySec is load-bearing. It defaults to 1 minute, so without it systemd may coalesce both firings into a single per-minute run — the unit reads correctly and fires half as often as you asked. See systemd timers.
Or use a dialect that has seconds
- Spring
@Scheduled(cron = "*/30 * * * * *")— see the Spring cron reference and the Spring @Scheduled guide. - Quartz
0/30 * * * * ?— see the Quartz cron reference.
For a pure interval, @Scheduled(fixedRate = 30000) or tokio::time::interval(Duration::from_secs(30)) says “every 30 seconds” without a cron parser.
This is the most-requested sub-minute interval — sub-minute scheduling covers the per-runtime support matrix and the crontab sleep 30 workaround in full.
Want an interval that doesn’t divide 60? See every 45 seconds for the non-divisor trap and its four-entry fix.
Frequently asked questions
What is the cron expression for every 30 seconds?
How do I run a cron job every 30 seconds on Linux?
Why doesn't `*/30 * * * *` run every 30 seconds?
How do I run something every 30 seconds in Spring Boot?
More seconds schedules
Other patterns on the same cadence — or browse every schedule.