Vivere

Vivere / Tools

Crontab expression explainer

Paste a cron expression. Read what it actually does, and when it actually runs.

Try: every 15 minutes · nightly at 02:00 · weekday mornings · first of the month · the confusing one · @weekly

Everything above happens in your browser. The expression is not sent to this server, is not logged and is not stored — a crontab line describes somebody's infrastructure, and it is not ours to collect.

How to read the five fields

┌───────── minute        0–59
│ ┌─────── hour          0–23
│ │ ┌───── day of month  1–31
│ │ │ ┌─── month         1–12  or JAN–DEC
│ │ │ │ ┌─ day of week   0–7   or SUN–SAT  (0 and 7 are both Sunday)
│ │ │ │ │
0 2 * * *   →  every day at 02:00

Within a field: * is every value, 5 is exactly five, 1-5 is a range, 1,15 is a list, and */10 is every tenth value. 5/15 means "from 5 to the end of the field, every 15".

The rule almost everyone gets wrong

When both the day-of-month and the day-of-week fields are restricted, cron runs the job if either matches — not both. 0 0 13 * 5 is not "Friday the 13th". It is "every 13th of the month, and every Friday", which is about 65 days a year rather than one or two.

If one of the two is *, the other simply applies, which is why 0 9 * * 1-5 behaves the way you expect. Try both in the box above and watch the run list change.

Things that catch people out

Knowing it actually ran

A correct expression is not the same as a job that runs. The crontab can be right while the machine is off, the entry is on a host that was rebuilt, the script exits non-zero, or the schedule is on a branch GitHub never looks at. Cron does not tell you about any of that.

Add one line to the job and Vivere tells you when a run does not happen:

0 2 * * * /srv/app/backup.sh && curl -fsS -m 10 --retry 3 -o /dev/null https://vivere.dev/p/<your-monitor-id>

What to check when a cron job stops running · How late should you let it be?