How Do Cron Jobs Work — The Scheduling Syntax That Trips Everyone Up

cron syntax — Chunky Munster

Cron syntax is the compact rule set that tells a scheduler when to run a task. It looks like machine noise until you map each field to minute, hour, day, month, and weekday. If you want to test a pattern instead of squinting at it, give the cron expression builder a spin.

What cron syntax actually does

Cron is not a little programming language. It is a time filter that gets checked against the clock on a fixed interval, and the job runs only when the current time matches the rule.

In the classic five-field format, the order is usually:

So 0 9 * * 1 means “run at 09:00 every Monday.” 30 2 * * * means “run every day at 02:30.” The asterisk means “any valid value,” which is why cron syntax is easier to read as a set of narrowing conditions than as code.

How to read the fields without getting lost

The cleanest way to read a cron expression is left to right, starting with the clock, then adding calendar constraints. First ask what minute and hour are allowed. Then ask whether the job is limited to certain days, months, or weekdays.

A few patterns show up constantly:

Two symbols do most of the work here: * means “match anything,” and / means “step through a range.” If you see */15 in the minute field, that means 0, 15, 30, and 45. Same idea for hours, days, or months.

There are also commas and dashes. Commas let you list discrete values, like 1,3,5. Dashes make ranges, like 9-17, which is handy when you want office hours without writing every hour manually.

The part everyone forgets: day of month vs day of week

This is where cron syntax gets weird enough to trip people up. The day of month and day of week fields are not always combined the way you expect. On many systems, if both fields are restricted, the job may run when either one matches, not only when both do.

That means 0 9 1 * 1 can behave differently depending on the implementation. If you want a job on the first of the month and on Mondays, confirm how your scheduler handles that combination. Some cron variants have stricter or more flexible rules than others.

Rule of thumb: if you can express the schedule with one of those fields left as *, do that. It cuts down on ambiguity and makes the intent obvious to the next person reading the file at 2 a.m.

Also remember that weekday numbering varies a bit by system. Many cron implementations accept both 0 and 7 for Sunday, while others document only one of them. When in doubt, test the expression in the actual environment.

Common cron syntax patterns you’ll actually use

Most schedules fall into a small handful of patterns. Once you recognize them, cron stops feeling like arcane shorthand and starts looking like a regular template.

  1. Every N minutes: */10 * * * *
  2. Once a day: 0 3 * * *
  3. Weekdays only: 0 9 * * 1-5
  4. First day of the month: 0 0 1 * *
  5. Specific months: 0 12 * 6,12 *

If you’re dealing with deployments, backups, and cleanup tasks, these are the building blocks. A backup at midnight, a log rotation every hour, a report export every weekday morning — all of that is just different combinations of the same five fields.

For a deeper background on the moving parts, our guide on how cron syntax works pairs nicely with the field-by-field breakdown here.

Timezone, drift, and why “midnight” can be slippery

Cron jobs do not care about your intent. They care about the system clock. If the server timezone changes, daylight saving time shifts, or the machine sleeps, the schedule may drift from what you expected.

That matters for jobs like billing exports, cache invalidation, and daily emails. A job that says “run at midnight” might suddenly fire at 23:00 or 01:00 relative to the audience you care about if the server is configured in UTC while your users are not.

When a task is business-critical, write down the timezone assumption next to the expression. Better yet, set the scheduler in the timezone you actually want, then verify the next run times after deployment.

For debugging time math, it can help to convert the target hour into the server’s local time first. If you need a quick cross-check, the clock on the machine is the truth source, not the human reading of the expression.

What happens when cron syntax is wrong

Bad cron syntax usually fails in one of three ways: it is rejected outright, it is accepted but does something different than you meant, or it runs at the wrong frequency. The last one is the dangerous version because it looks valid until the log flood starts.

Typical mistakes include:

When a job misfires, inspect the expression from left to right and check the next expected run against the system’s scheduler docs. The syntax itself is short; the implementation details are where the bugs hide.

One practical habit: keep the cron string beside a plain-English comment.

# Run every weekday at 09:00 server time
0 9 * * 1-5

That way, even if someone edits the schedule later, the intent is visible without reverse-engineering the fields again.

A Worked Example

Say you need a job that runs every weekday at 6:30 PM, but never on weekends. You could write it as a single cron expression and pair it with a simple explanation in the config file.

# Send summary email every weekday at 18:30
30 18 * * 1-5

Breakdown: 30 is the minute, 18 is 6 PM in 24-hour time, and 1-5 limits the run to Monday through Friday. The day of month and month are both wildcards, so the job is not restricted by date.

Now compare that with a monthly cleanup job:

# Purge old temp files on the first day of every month at 03:00
0 3 1 * *

Here, the scheduler is watching for hour 3, minute 0, and day 1. Everything else is open-ended. If you read it backwards, the job runs “at 03:00 on day 1 of any month.”

That pattern is the core of cron syntax: start with the exact clock time, then add only the calendar limits you need. If the schedule gets more complicated than that, it is usually a sign you should split the work into smaller jobs instead of forcing one expression to do gymnastics.

Frequently Asked Questions

What does the asterisk mean in cron syntax?

The asterisk means “any valid value” for that field. In * * * * *, every field is unrestricted, so the job runs every minute. It is the most common wildcard and the easiest way to say “don’t filter this part of time.”

Is cron syntax the same everywhere?

No. The five-field format is common, but the exact rules can vary between cron implementations. Some systems support extra fields for seconds or year, and the weekday numbering can differ slightly. Always check the scheduler docs for the environment you are actually using.

How do I run a cron job every 15 minutes?

Use */15 * * * *. That means every 15 minutes past each hour: 00, 15, 30, and 45. It does not mean “15 times a day” or “at minute 15 only.”

Why does my cron job run on the wrong day?

The usual culprit is the weekday field, a timezone mismatch, or confusion between day-of-month and day-of-week behavior. If the server uses UTC but you expected local time, the job will look off by several hours. Also confirm whether your cron implementation treats the date fields as an OR or AND condition.

The Bottom Line

Cron syntax is small, but it carries a lot of scheduling intent. Once you map each field to the clock and the calendar, the weirdness drops away and the patterns become predictable.

The safest way to work is simple: write the expression, add a plain-English comment, and verify the next few run times before you ship it. If you are building or debugging a schedule, use this cron expression builder tool to test the timing before the job starts wandering around your server logs.

That extra minute of checking is cheaper than a backup that runs at lunch or a cleanup task that never shows up. Cron is blunt machinery. Treat it like one.

// try the tool
give the cron expression builder a spin →
// related reading
← all posts