What Are Cron Expressions?
Cron expressions are compact text strings used to define schedules for recurring tasks. They originated in the Unix cron utility, which has been a standard component of Unix-like operating systems since the 1970s. A cron expression specifies when a task should run using five (or six) fields representing different units of time. Despite their cryptic appearance, cron expressions follow a logical pattern that, once understood, provides a powerful and flexible way to schedule any recurring task.
The classic cron expression format consists of five space-separated fields: minute, hour, day of month, month, and day of week. Some implementations add a sixth field for seconds or years. Each field can contain specific values, ranges, lists, intervals, or wildcards. The expression 0 9 * * 1-5, for example, means "run at 9:00 AM every weekday" (Monday through Friday).
Cron expressions are used far beyond traditional Unix systems. They are found in job scheduling frameworks in Java (Quartz, Spring), Python (APScheduler, Celery Beat), JavaScript (node-cron), cloud platforms (AWS EventBridge, Google Cloud Scheduler), and virtually every CI/CD pipeline tool. Understanding cron expressions is an essential skill for any developer or system administrator.
Anatomy of a Cron Expression
A standard five-field cron expression has the following structure:
┌───────────── minute (0 - 59) │ ┌───────────── hour (0 - 23) │ │ ┌───────────── day of month (1 - 31) │ │ │ ┌───────────── month (1 - 12) │ │ │ │ ┌───────────── day of week (0 - 6, 0 = Sunday) │ │ │ │ │ * * * * *
Field Values and Operators
- Asterisk (*): Matches any value.
* * * * *means every minute of every hour of every day. - Comma (,): Specifies a list of values.
0 9,18 * * *means 9:00 AM and 6:00 PM every day. - Hyphen (-): Specifies a range.
0 9-17 * * *means every hour from 9 AM to 5 PM. - Slash (/): Specifies intervals.
*/15 * * * *means every 15 minutes.0 */2 * * *means every 2 hours. - Specific values: Exact numbers.
30 14 * * *means 2:30 PM every day.
Day of Week Values
0 or SUN = Sunday 1 or MON = Monday 2 or TUE = Tuesday 3 or WED = Wednesday 4 or THU = Thursday 5 or FRI = Friday 6 or SAT = Saturday 7 or SUN = Sunday (also accepted)
Common Cron Expression Examples
* * * * * Every minute 0 * * * * Every hour (at minute 0) */15 * * * * Every 15 minutes 0 */2 * * * Every 2 hours 0 0 * * * Every day at midnight 0 9 * * * Every day at 9:00 AM 0 9 * * 1-5 Every weekday at 9:00 AM 0 9 * * 0,6 Every Saturday and Sunday at 9:00 AM 0 0 1 * * On the 1st of every month at midnight 0 0 1 1 * On January 1st at midnight 0 0 * * 0 Every Sunday at midnight 30 14 15 * * On the 15th of every month at 2:30 PM 0 0 1,15 * * On the 1st and 15th of every month */5 9-17 * * 1-5 Every 5 minutes during business hours on weekdays 0 6 1 1,4,7,10 * On the 1st of Jan, Apr, Jul, Oct at 6:00 AM
Cron in Different Environments
Linux/Unix Crontab
The original cron system uses crontab files to define scheduled tasks. Each user can have their own crontab, and there is a system-wide crontab for administrative tasks.
# Edit your crontab crontab -e # Example entries: # Run backup script every day at 2 AM 0 2 * * * /home/user/scripts/backup.sh # Run cleanup every Sunday at midnight 0 0 * * 0 /home/user/scripts/cleanup.sh # Send report every weekday at 9 AM 0 9 * * 1-5 /home/user/scripts/daily-report.sh
Crontab entries also support convenience shortcuts:
@yearly = 0 0 1 1 * (once a year) @annually = 0 0 1 1 * (same as @yearly) @monthly = 0 0 1 * * (once a month) @weekly = 0 0 * * 0 (once a week) @daily = 0 0 * * * (once a day) @hourly = 0 * * * * (once an hour) @reboot = (run at startup)
Node.js with node-cron
const cron = require("node-cron");
// Run every weekday at 9 AM
cron.schedule("0 9 * * 1-5", () => {
console.log("Running daily report...");
});
// Run every 30 minutes
cron.schedule("*/30 * * * *", () => {
console.log("Checking status...");
});
Python with APScheduler
from apscheduler.schedulers.blocking import BlockingScheduler scheduler = BlockingScheduler() # Run every weekday at 9 AM scheduler.add_job(daily_report, "cron", hour=9, day_of_week="mon-fri") # Run every 15 minutes scheduler.add_job(check_status, "cron", minute="*/15") scheduler.start()
Java with Spring
@Component
public class ScheduledTasks {
// Every weekday at 9 AM
@Scheduled(cron = "0 9 * * MON-FRI")
public void dailyReport() {
System.out.println("Running daily report...");
}
// Every 30 minutes
@Scheduled(cron = "0 */30 * * * *")
public void checkStatus() {
System.out.println("Checking status...");
}
}
Advanced Cron Patterns
The Last Day of the Month
One common challenge is scheduling a task for the last day of the month, since months have different lengths. The "L" modifier (supported by Quartz and some other implementations) addresses this:
# Last day of every month (Quartz syntax) 0 0 L * * # Last Friday of every month (Quartz syntax) 0 0 ? * 6L
In standard Unix cron, there is no built-in "L" modifier. A common workaround is to run the task every day and include a check in the script for whether tomorrow is the first of the month.
The Nearest Weekday
The "W" modifier (Quartz) runs the task on the nearest weekday if the specified date falls on a weekend:
# 15th of every month, or nearest weekday if 15th is a weekend 0 0 15W * *
Expression with Hash (nth occurrence)
The "#" modifier (Quartz) specifies the nth occurrence of a day of week within a month:
# Third Friday of every month 0 0 ? * 6#3 # Second Monday of every month 0 0 ? * 2#2
Common Pitfalls and Mistakes
- Timezone issues: Cron expressions run in the server's local timezone unless explicitly configured otherwise. Always specify the timezone when deploying across regions. Use
CRON_TZin Linux or timezone parameters in your scheduling framework. - Day of month AND day of week: In standard cron, if both day of month AND day of week are specified (not *), the task runs when EITHER matches, not both. This is counterintuitive. Quartz cron uses "?" to indicate "no specific value" for one of the two fields to avoid this ambiguity.
- Overlapping executions: If a cron task takes longer than its interval, subsequent executions may overlap. Use locking mechanisms or frameworks that support preventing concurrent execution of the same job.
- Daylight Saving Time: Clock changes can cause cron jobs to run twice, be skipped, or run at unexpected times. Use UTC for critical schedules to avoid DST issues.
- Logging and monitoring: Always log cron job execution and failures. Silent failures in cron jobs are notoriously difficult to debug because there is no user interface to check.
How to Build a Cron Schedule
Using an Online Cron Generator
Our free online cron expression generator lets you build cron schedules using a friendly interface. Select the desired schedule from dropdowns and presets, and the tool generates the correct cron expression with a human-readable description. It supports both standard 5-field and Quartz 6-field formats.
Step-by-Step Approach
When building a cron expression manually, work from right to left. Start with the broadest constraint (month or day of week) and narrow down to the specific minute. For example, to schedule "every weekday at 2:30 PM":
- Day of week:
1-5(Monday through Friday) - Month:
*(every month) - Day of month:
*(any day) - Hour:
14(2 PM in 24-hour format) - Minute:
30 - Result:
30 14 * * 1-5
Cron Expression Quick Reference
Schedule Expression ──────────────────────────────────────────────────── Every minute * * * * * Every 5 minutes */5 * * * * Every hour 0 * * * * Every 2 hours 0 */2 * * * Every day at midnight 0 0 * * * Every day at 6:30 AM 30 6 * * * Every Monday at 9 AM 0 9 * * 1 Every weekday at 9 AM 0 9 * * 1-5 First day of every month 0 0 1 * * Every Sunday at noon 0 12 * * 0 Every quarter (Jan, Apr, Jul, Oct) 0 0 1 1,4,7,10 * Every Friday the 13th (Quartz) 0 0 13 * ? 5
Best Practices for Cron Scheduling
- Use UTC for critical schedules. Avoid timezone and DST issues by running important cron jobs in UTC.
- Implement idempotency. Design cron jobs so that running them multiple times with the same input produces the same result. This handles overlaps gracefully.
- Add monitoring and alerting. Set up notifications for cron job failures. A silent failure is the most dangerous kind.
- Log execution details. Record start time, end time, and outcome for every cron job execution.
- Use descriptive comments. In crontab files, always add comments explaining what each job does and why it runs on that schedule.
- Test before deploying. Verify your cron expression using an online tool before putting it into production.
Try our free online tool to get results instantly in your browser.
Frequently Asked Questions
What is a cron expression?
A cron expression is a text string of five or six fields separated by spaces that defines a recurring schedule. The fields represent minute, hour, day of month, month, and day of week. For example, '0 9 * * 1-5' means 9:00 AM every weekday.
How do I schedule a task to run every 5 minutes?
Use the cron expression: */5 * * * *. The */5 in the minute field means 'every 5 minutes.' This works in all standard cron implementations including Linux crontab, node-cron, and Spring Scheduler.
What is the difference between standard cron and Quartz cron?
Standard Unix cron uses 5 fields (minute, hour, day, month, weekday). Quartz cron uses 6 fields, adding seconds at the beginning. Quartz also supports additional modifiers like L (last), W (nearest weekday), and # (nth occurrence) that are not available in standard cron.
How do I run a cron job on the last day of the month?
In Quartz cron, use: 0 0 L * *. Standard Unix cron does not have a 'L' modifier. The workaround is to run daily and check in your script if tomorrow is the 1st of the month, which means today is the last day.
Why does my cron job not run at the expected time?
Common reasons include: timezone mismatch (cron uses server timezone), DST changes, both day-of-month and day-of-week specified (standard cron uses OR logic), or the cron daemon not running. Check 'systemctl status cron' on Linux.