Understanding CRON Expressions with Examples

CRON expressions are five-field strings that tell a scheduler exactly when to run a task. They look cryptic at first β€” */5 * * * * β€” but the logic is completely regular once you know what each field means. This guide walks through all five fields, every special character, and thirty real-world examples you can copy and test immediately.

Want to build or test a CRON expression visually?

Open CRON Expression Generator β†’

The five fields

A standard CRON expression has exactly five fields, separated by spaces:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ minute        (0–59)
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ hour          (0–23)
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€ day of month  (1–31)
β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€ month         (1–12)
β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€ day of week   (0–6, 0 = Sunday)
β”‚ β”‚ β”‚ β”‚ β”‚
* * * * *

So 30 8 * * 1 means: at minute 30, hour 8, any day of month, any month, only on Monday β€” which is "every Monday at 8:30 AM".

Special characters

* β€” every value

An asterisk matches every possible value for that field.

* * * * *   β†’ runs every minute

*/n β€” every n-th value (step)

The slash means "step". */5 means every 5th value starting from the minimum. In the minute field that is 0, 5, 10, 15, …, 55.

*/5  * * * *   β†’ every 5 minutes
*   */2 * * *   β†’ every 2 hours (00:00, 02:00, 04:00, …)
*/30 * * * *   β†’ every 30 minutes

n-m β€” range

A hyphen defines a continuous range of values, inclusive.

0 9 * * 1-5   β†’ weekdays (Mon–Fri) at 9:00 AM
0 8-18 * * *  β†’ every hour from 8 AM to 6 PM

n,m,p β€” list

Comma-separated values specify multiple discrete values. No spaces around the commas.

0 9,17 * * *      β†’ 9:00 AM and 5:00 PM every day
0 0 1,15 * *      β†’ midnight on the 1st and 15th of each month

n-m/p β€” range with step

Combines a range and a step: matches every p-th value within the range n through m.

0-30/10 * * * *   β†’ minutes 0, 10, 20, 30 of every hour
0 8-18/2 * * *    β†’ every 2 hours between 8 AM and 6 PM

Common schedules β€” ready to copy

Expression Meaning
* * * * *Every minute
*/5 * * * *Every 5 minutes
*/15 * * * *Every 15 minutes
0 * * * *At the start of every hour
0 0 * * *Every day at midnight
0 6 * * *Every day at 6:00 AM
0 9 * * 1-5Weekdays at 9:00 AM
0 9,17 * * 1-5Weekdays at 9 AM and 5 PM
0 0 * * 0Every Sunday at midnight
0 0 * * 1Every Monday at midnight
0 0 1 * *First day of every month at midnight
0 0 1,15 * *1st and 15th of every month at midnight
0 0 L * *Last day of the month (Linux cron / Quartz only)
0 0 1 1 *January 1st at midnight (yearly)
0 */4 * * *Every 4 hours (midnight, 4 AM, 8 AM, …)
30 23 * * *Every day at 11:30 PM
0 8-18 * * 1-5Business hours (8 AM–6 PM, Mon–Fri)
0 0 * * 6,0Every weekend (Sat and Sun) at midnight

Day-of-month vs day-of-week: the OR rule

One of the most confusing behaviours in CRON: if both the day-of-month and day-of-week fields are set to something other than *, most systems use OR logic, not AND.

For example, 0 0 15 * 1 runs at midnight on the 15th of every month and also on every Monday. If you wanted "the 15th only if it is a Monday", you cannot express that in a standard CRON expression β€” you would need to handle it inside the script itself.

If one of the two fields is *, the OR rule collapses to the non-wildcard field only. So 0 0 15 * * runs only on the 15th, and 0 0 * * 1 runs only on Mondays.

How CRON handles time zones

Classic crontab on Linux always uses the server's local time zone (set by /etc/timezone or the TZ environment variable). Cloud schedulers like AWS EventBridge, GitHub Actions scheduled workflows, and Google Cloud Scheduler default to UTC.

The safe default: always write CRON expressions in UTC and document the UTC offset alongside the job definition. This avoids surprises when daylight saving time shifts clocks by an hour β€” a job set to run "at 2:00 AM" will either skip or run twice on DST changeover days if the schedule is in local time.

CRON in cloud and CI environments

CRON syntax is ubiquitous in modern infrastructure:

  • GitHub Actions β€” on: schedule: cron: "0 9 * * 1" triggers a workflow every Monday at 9:00 UTC.
  • AWS EventBridge (CloudWatch Events) β€” uses the same five-field syntax but adds a 6th field for seconds in some places.
  • Kubernetes CronJob β€” the spec.schedule field accepts a standard five-field expression.
  • Google Cloud Scheduler β€” accepts standard CRON expressions, runs in UTC by default (configurable per job).
  • Heroku Scheduler β€” limited syntax; supports only every 10 minutes, every hour, and every day at HH:00.

Why expressions are harder to read than they look

A few traps that catch even experienced engineers:

  • Month and weekday are 1-based and 0-based respectively. Month 1 is January; weekday 0 is Sunday (not Monday). Some implementations also accept 7 as Sunday β€” check your platform's docs.
  • Minutes come first, not hours. It is easy to swap them. 0 8 * * * is 8:00 AM; 8 0 * * * is 0:08 AM.
  • Ranges are inclusive on both ends. 1-5 in the weekday field means Monday through Friday, and includes both 1 and 5.
  • */n starts from zero (or the field minimum). */7 in the day-of-month field matches days 1, 8, 15, 22, 29 β€” not "every 7 days from today".

Testing before you deploy

Getting a CRON expression wrong is easy. Getting the consequences wrong β€” a billing job that runs every minute instead of every month β€” is expensive. Always test before deploying:

  1. Use the CRON Expression Generator on this site to see the plain-English description and the next 5 scheduled datetimes.
  2. On Linux, use cronitor select or install cron-descriptor (pip install cron-descriptor) to convert an expression to English at the command line.
  3. In Node.js, cron-parser (npm install cron-parser) lets you iterate over the next N fire times programmatically.
  4. For Kubernetes CronJobs, run a manual job first (kubectl create job --from=cronjob/<name>) to validate the job script itself before the schedule triggers it.

Quick reference: all special characters

Character Name Example Meaning
*Wildcard*Every value
*/nStep*/5Every 5th value (0, 5, 10, …)
-Range1-5Values 1 through 5 inclusive
,List1,15Values 1 and 15
n-m/pRange + step8-18/2Every 2nd value from 8 to 18

Summary

CRON expressions follow a consistent five-field pattern: minute hour day-of-month month day-of-week. Master the four special characters (*, /, -, ,) and you can express almost any recurring schedule. The main pitfalls are field order confusion, the month/weekday OR rule, and time zone assumptions β€” all of which you can catch before deploying by running the expression through a tester and reading the plain-English description.

Ready to build or test your CRON expression?

Open CRON Expression Generator β†’