If you have ever needed to automate a task on a server, schedule a database backup, or trigger a webhook at a specific time, you have almost certainly encountered cron expressions. These compact strings of numbers and symbols are the backbone of task scheduling on Linux systems and are widely used in modern web frameworks like Spring, Node.js, and Quartz. Yet for many developers, cron syntax remains a source of confusion and occasional bugs.
This guide will walk you through everything you need to know about cron expressions — from the basic structure to advanced patterns — and show you how to use a cron expression generator to build schedules quickly and accurately.
A cron expression is a string composed of five or six fields separated by spaces. Each field represents a unit of time, and together they define a schedule for when a task should execute. The standard Unix cron format uses five fields:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 7, where 0 and 7 = Sunday)
│ │ │ │ │
* * * * *
Some implementations (such as Quartz Scheduler used in Java/Spring) add a sixth field at the beginning for seconds:
┌───────────── second (0 - 59)
│ ┌───────────── minute (0 - 59)
│ │ ┌───────────── hour (0 - 23)
│ │ │ ┌───────────── day of month (1 - 31)
│ │ │ │ ┌───────────── month (1 - 12)
│ │ │ │ │ ┌───────────── day of week (0 - 7)
│ │ │ │ │ │
0 0 12 * * ?
Each field in a cron expression accepts specific operators and values. Understanding these operators is the key to reading and writing any cron schedule.
| Operator | Description | Example | Meaning |
|---|---|---|---|
* | Asterisk (any value) | * * * * * | Every minute of every hour |
, | Comma (list separator) | 0 9,18 * * * | At 9:00 and 18:00 |
- | Hyphen (range) | 0 9-17 * * * | Every hour from 9 to 17 |
/ | Slash (step values) | */15 * * * * | Every 15 minutes |
? | Question mark (no specific value) | 0 0 * * ? | Any day (used in Quartz) |
L | Last | 0 0 L * * | Last day of month |
W | Weekday | 0 0 15W * * | Nearest weekday to 15th |
# | Nth day of month | 0 0 ? * 6#3 | Third Friday of month |
Here is a reference table of the most frequently used cron patterns. You can use these as starting points for your own schedules.
| Expression | Description |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes |
0 * * * * | Every hour (at minute 0) |
0 */2 * * * | Every 2 hours |
0 0 * * * | Every day at midnight |
0 6 * * * | Every day at 6:00 AM |
0 0 * * 0 | Every Sunday at midnight |
0 0 1 * * | On the 1st of every month |
0 0 1 1 * | January 1st at midnight |
30 14 * * 1-5 | Weekdays at 2:30 PM |
0 9,12,18 * * * | Three times daily: 9 AM, 12 PM, 6 PM |
*/10 9-17 * * 1-5 | Every 10 min during business hours (Mon–Fri) |
Follow this simple process to build any cron expression from scratch.
Before writing a single character, clearly define what you need. For example: "Send a daily report email every weekday at 8:30 AM."
Working left to right, fill in each field based on your requirement:
30 8 * * 1-5
Always validate your expression before putting it into production. Use our cron expression generator to verify that the schedule matches your intent and preview upcoming execution times.
?. This is a common source of confusion when migrating between systems.
The traditional way to manage cron jobs on Linux is through the crontab command. Edit your user's crontab with crontab -e and add lines in this format:
# Daily database backup at 2:00 AM
0 2 * * * /usr/bin/mysqldump -u root mydb > /backups/db_$(date +\%Y\%m\%d).sql
# Cleanup temp files every Sunday at 4:00 AM
0 4 * * 0 find /tmp -type f -mtime +7 -delete
In Node.js applications, the node-cron package lets you schedule tasks using a six-field format (with seconds):
const cron = require('node-cron');
// Run every weekday at 9:00 AM
cron.schedule('0 9 * * 1-5', () => {
console.log('Generating daily report...');
});
Spring uses Quartz-style expressions with six fields and requires ? for unspecified day fields:
@Scheduled(cron = "0 0 12 * * ?")
public void dailyNoonTask() {
// Runs every day at noon
}
Python's APScheduler supports cron-style triggers with an expressive API:
from apscheduler.schedulers.blocking import BlockingScheduler
scheduler = BlockingScheduler()
scheduler.add_job(my_task, 'cron', hour=8, minute=30, day_of_week='mon-fri')
scheduler.start()
Remember that cron uses 0-based indexing for minutes and hours. 0 is the first minute/hour, not 1. However, days of month and months are 1-based. This inconsistency trips up even experienced developers.
Cron expressions do not contain timezone information. The server's local timezone determines when the job runs. If your server uses UTC but you need a schedule in EST, you must convert the time manually. For example, 9:00 AM EST = 14:00 UTC (during standard time).
When clocks spring forward or fall back, cron jobs can behave unexpectedly. A job scheduled for 2:30 AM might not run at all on the "spring forward" day, or run twice on the "fall back" day. Consider this when scheduling time-sensitive tasks near DST transitions.
Always redirect output to a log file. A silent cron job that fails silently is nearly impossible to debug:
0 2 * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
Use L in Quartz-style expressions:
0 0 L * ? # Last day of month at midnight
Use W to find the closest weekday to a given date:
0 0 15W * ? # Nearest weekday to the 15th
Use # to specify the nth occurrence of a weekday in a month:
0 0 ? * 5#2 # Second Thursday of every month
Linux cron uses five fields (no seconds) and treats * in both day fields as "any." Quartz cron uses six fields (with seconds) and requires ? instead of * when one day field is left unspecified. Quartz also supports additional operators like L, W, and #.
Standard cron expressions support a minimum granularity of one minute (or one second in Quartz). For sub-second or sub-minute scheduling, consider using a dedicated task queue like Celery, Bull, or a simple setInterval in your application code.
Check these common issues: verify the expression syntax, ensure the script has execute permissions (chmod +x), check that the server's cron daemon is running (systemctl status cron), and inspect system logs (grep CRON /var/log/syslog).
Some implementations (notably Quartz) support an optional year field as the last position. For example, 0 0 0 1 1 ? 2026 would run only on January 1, 2026. Standard Linux cron does not include a year field.
Stop guessing cron syntax. Use our free Cron Expression Generator to build, validate, and preview schedules instantly.
Open Cron Generator →Cron expressions are a powerful and widely adopted tool for scheduling tasks. While the syntax can look cryptic at first glance, it follows a logical structure that becomes intuitive with practice. By understanding the five fields, the operators, and the common patterns covered in this guide, you will be able to confidently write and troubleshoot cron schedules for any environment.
When in doubt, use a cron expression generator to build your schedule visually, preview upcoming execution times, and catch errors before they reach production. Scheduling should save you time — not consume it.