Cron expression for Every 20 minutes
*/20 * * * *
Runs every 20 minutes, around the clock.
Next 5 runs (your local time)
These are shown in your browser’s timezone. The job itself runs in the scheduler’s timezone — often UTC — so the real run time can differ.
What people actually schedule with */20 * * * *
- Pulling fresh exchange rates, weather, or other slow-changing feeds where hourly is too stale but minute-level is pointless
- Running a moderate-cost ETL increment that needs three passes per hour to keep a dashboard reasonably current
- Sweeping for abandoned-cart or stuck-job records on a cadence that catches them within a coffee break
Use */20 * * * * on your platform
It’s the same 5-field expression everywhere — what changes is where you put it and which timezone it runs in.
Linux / crontab
*/20 * * * * /path/to/your-command
Runs in the server’s local timezone — check it with timedatectl.
Full field reference: crontab(5) man page.
GitHub Actions
on:
schedule:
- cron: "*/20 * * * *"
GitHub Actions always runs scheduled jobs in UTC — there is no timezone setting, and runs can be delayed under load (official docs).
Kubernetes CronJob
spec:
schedule: "*/20 * * * *"
Defaults to UTC. Set spec.timeZone (Kubernetes 1.27+)
for a specific zone — see the
CronJob docs.
Quartz / Spring @Scheduled
Quartz uses 6 fields (seconds first): 0 */20 * * * *. Watch out:
Quartz day-of-week is 1=SUN … 7=SAT (not 0–6), and day-of-month /
day-of-week use ? — double-check if your schedule touches those fields
(Quartz cron reference).
Gotchas with every 20 minutes schedules
- Use
*/20, not0,20,40, but know they're identical here. Both fire at :00,:20,:40 because 20 divides 60 cleanly — unlike 45-minute attempts, this one is honest. The real gotcha is assuming*/20means '20 minutes after the job started'; it's fixed to the clock, so a run starting at :19:58 is immediately followed by the :20:00 fire. - Three runs an hour makes timezone-sensitive windows sneaky. If the job reports 'last 20 minutes of activity' and your server runs UTC while your business runs Pacific, the boundary buckets won't line up with what stakeholders see in their local dashboards — pin the reporting window to an explicit TZ, not server local time.
- Long jobs silently merge buckets. If a run regularly takes 8+ minutes and occasionally spikes to 22, it bleeds into the next slot; add
flock -n /tmp/etl.lockso the :20 run skips cleanly rather than running two ETL passes against the same window.
Will you know if this job silently fails?
Cron jobs fail quietly — a server reboots, a path changes, or an error code is ignored — and nobody notices until the data is missing. A cron monitor (a dead-man’s-switch) alerts you when a scheduled job does not check in on time.
Monitor your cron jobs with UptimeRobot →
Disclosure: this is an affiliate link — we may earn a commission if you sign up, at no extra cost to you.
Is */20 * * * * the right schedule?
If the feed barely changes, every 30 minutes halves the load with little freshness cost; if you need tighter currency, every 15 minutes gives you four clean quarter-hour buckets that align nicely with reporting tools.
Or use the interactive cron generator & explainer, read the complete cron syntax guide, or pick another common schedule: