Cron Expressions: Read and Write Them in 5 Minutes

Cron expressions look like line noise, five cryptic fields that decide when servers do things, and yet the whole syntax fits on an index card. This guide teaches you to read and write them in one sitting: the five fields, the four special characters, the handful of expressions that cover ninety percent of real schedules, and the two traps that have paged more engineers at 3 AM than any other line of configuration. When you want to skip the theory, our free crontab generator builds the expression from dropdowns, and the cron parser shows you exactly when it will fire.

The five fields, left to right

A cron expression is five values separated by spaces, each answering one question about time:

PositionFieldAllowed values
1Minute0 to 59
2Hour0 to 23
3Day of month1 to 31
4Month1 to 12
5Day of week0 to 6, Sunday is 0

Reading is a sentence template: “at minute __ of hour __, on day __ of month __, in month __, on weekday __”. So 30 14 * * * reads “at minute 30 of hour 14, every day”: daily at 2:30 PM. The order trips newcomers because the smallest unit comes first, the opposite of how humans say times, which is exactly why reading the fields aloud as the template is worth the thirty seconds it takes.

The four special characters

Four symbols do all the work. The asterisk * means “every value”, the wildcard that makes a field irrelevant. The comma , lists values: 0,30 in the minute field means on the hour and half hour. The hyphen - spans a range: 1-5 in the weekday field means Monday through Friday. The slash / steps: */15 in the minute field means every 15 minutes, which works out to exactly 96 runs per day. The symbols combine, so 0 8-18/2 * * 1-5 means on the hour, every second hour from 8 to 18, weekdays only. When a combination starts needing a sentence that long, build it in the generator instead of by hand.

The expressions you will actually use

ExpressionMeaning
*/15 * * * *every 15 minutes, 96 times a day
0 * * * *top of every hour
0 9 * * 1-5weekdays at 9:00 AM
0 0 * * *daily at midnight
30 2 * * 0Sundays at 2:30 AM
0 0 1 * *first of the month, midnight
0 */6 * * *at 00:00, 06:00, 12:00, 18:00

These seven patterns, with values swapped, cover nearly every backup, report, cleanup and sync job in production anywhere. Notice what they share: the minute field is always pinned to a number. The moment you understand why, you have understood the first trap.

The two classic traps

Trap one: the unpinned minute. Someone wants “daily at 9 AM” and writes * 9 * * *. The asterisk means every minute, so the job runs 60 times, once per minute, through the entire nine o’clock hour. The report email arrives 60 times; if the job is expensive, the server has a bad morning. The rule: a schedule of “once at” must pin the minute, 0 9 * * *, and anytime you see an asterisk in the first field, the job runs at least every minute of whatever else matches.

Trap two: day-of-month and day-of-week combine with OR, not AND. 0 0 1 * 1 looks like “midnight on the first of the month, if it is a Monday”. Standard cron actually runs it on the first of every month and on every Monday, both, because when those two fields are each restricted, matching either one triggers the job. This is the most counterintuitive rule in cron, it is original Unix behavior, and the practical advice is simply never to restrict both fields in one expression. A bonus trap worth one sentence: jobs scheduled between 2 and 3 AM can skip or double-run on daylight saving transition nights, so back up at 1:30 or 3:30 instead.

Shortcuts, and checking your work

Most cron implementations accept shorthand for the common cases: @hourly, @daily, @weekly, @monthly, and the special @reboot, which runs once at startup and is the standard way to launch something whenever a server restarts. Shorthands are readable, but they cannot express “weekdays at 9”, so the five fields stay necessary.

However the expression was written, verify it before trusting it: paste it into the cron parser and read the next actual run times it computes. Both traps above are invisible in the syntax and obvious in the output, sixty runs where you expected one, or a Monday run you never asked for. Thirty seconds of checking against the calendar in your head is the entire quality assurance a cron schedule needs, and the same local-first habit applies to the rest of the toolbox in the developer tools pillar.

Frequently asked questions

Is 7 a valid value for Sunday?

In most modern crons, yes: both 0 and 7 mean Sunday. Some older or stricter systems accept only 0, so 0 is the portable choice. Names like MON and SUN also work in many implementations, with the same portability caveat.

Can cron run a job every 30 seconds?

Not directly: one minute is cron’s finest resolution. The traditional workaround is two crontab entries running the same script, one plain and one wrapped in a 30-second sleep. If a task needs second-level precision, cron is the wrong tool and a proper scheduler or daemon is the right one.

My expression is correct but the job never runs. Why?

Usually environment, not schedule: cron runs jobs with a minimal PATH and none of your shell profile, so a script that works in your terminal can fail to find its commands under cron. Use absolute paths inside scripts and check the mail or log cron writes on failure. The other classic cause: a machine that was asleep or off at the scheduled time, since plain cron does not run missed jobs after the fact.

Why do some cron expressions have six fields?

Extended dialects add fields: Quartz and Spring schedulers prepend seconds, and some systems append a year. The five-field form in this guide is the classic Unix crontab syntax; when a platform shows six or seven fields, check its documentation for which end gained the extra one.

ATV

Written by Nick (ATV Team)

We build and maintain the 600+ free, client-side tools on this site, and every guide is written against the tools themselves: each figure is computed and checked before it is published, and every linked tool is tested in the browser. More about how we work on the about page, and the full library of guides lives on the blog.