devkult_
tools24converters26
home/blog/cron-expressions-explained
cronschedulingdevops

Cron Expressions Explained, Field by Field

*/15 * * * * is one of those strings you copy from Stack Overflow and hope it does what you think. Cron expressions are actually simple once you see them as five independent fields, each answering a single question about when. Let's take them apart.

The five fields

A standard cron expression is five space-separated fields:

┌───────────── minute        (0–59)
│ ┌─────────── hour          (0–23)
│ │ ┌───────── day of month  (1–31)
│ │ │ ┌─────── month         (1–12 or JAN–DEC)
│ │ │ │ ┌───── day of week    (0–6 or SUN–SAT; 0 and 7 are both Sunday)
│ │ │ │ │
* * * * *

Each field is matched independently. The job runs when all fields match the current time. So 0 9 * * * reads as: minute 0, hour 9, any day, any month, any weekday → "every day at 09:00."

The special characters

Four symbols do most of the work:

  • *any value. * * * * * matches every minute.
  • ,a list. 0,30 in the minute field means "at :00 and :30."
  • -a range. 9-17 in the hour field means "every hour from 9 through 17."
  • /a step. */15 in the minute field means "every 15 minutes." You can combine it with a range: 0-30/10 is "every 10 minutes from :00 to :30."

A few worked examples:

*/15 * * * *     every 15 minutes
0 0 * * *        every day at midnight
30 9 * * 1-5     09:30, Monday through Friday
0 */2 * * *      every 2 hours, on the hour
0 0 1 * *        midnight on the 1st of every month
15,45 8 * * *    at 08:15 and 08:45

If you'd rather not parse these by eye, paste any expression into the crontab explainer — it describes the schedule in plain English and lists the next five run times.

The gotcha: day-of-month AND day-of-week

This is the rule that surprises almost everyone. When both the day-of-month field and the day-of-week field are restricted (neither is *), standard cron treats them as an OR, not an AND.

0 0 1 * MON

You might read that as "midnight on the 1st, but only if it's a Monday." It actually means "midnight on the 1st of the month OR every Monday." The job fires on far more days than you'd expect.

The reason is historical, baked into the original Unix cron, and most schedulers preserve it for compatibility. The safe rule: if you need a precise "the 1st only when it's a Monday," handle that logic inside your job, not in the cron fields.

Minutes matter: cron's smallest unit

Standard cron resolves to the minute — there's no "every 30 seconds" in a five-field expression. Some schedulers add a sixth seconds field at the front (*/30 * * * * *), but that's an extension, not standard cron. If you need sub-minute timing, you usually want a different tool.

Test before you trust

A cron typo can mean a job that never runs, or one that runs a hundred times more than intended. Before committing an expression to a crontab or a CI schedule, check it against the next-run times — the crontab explainer shows both the human-readable meaning and the upcoming fire times so you can confirm it matches your intent.

Five fields, four symbols, one OR-rule to remember. That's the whole language.

More from the blog