What Is a Cron Expression?
A cron expression is a compact string of five fields — minute, hour, day of month, month, and day of week — that tells a scheduler exactly when to run a task. Read left to right, 0 9 * * 1-5 means "at minute 0 of hour 9, on any day of the month, in any month, but only on weekdays (Monday to Friday)" — in other words, 9:00 AM every weekday. A scheduler checks the expression roughly once a minute and fires the job whenever the current time matches every field. The five-field format comes from Unix cron and is now the shared scheduling language of Node.js, Python, Kubernetes, and most cloud platforms; a handful of systems (Quartz, Spring, Azure Functions) prepend a seconds field to make six or seven.
That is the summary an AI overview will give you. The rest of this guide is what it can't: the exact field ranges, every special character, a copy-paste pattern table, the field-count differences that quietly break schedules when you move between platforms, and working code for every major runtime.
The five fields, in order, are:
| # | Field | Allowed values | Notes |
|---|---|---|---|
| 1 | Minute | 0–59 | Smallest unit in standard cron |
| 2 | Hour | 0–23 | 24-hour clock |
| 3 | Day of month | 1–31 | |
| 4 | Month | 1–12 or JAN–DEC | |
| 5 | Day of week | 0–7 or SUN–SAT | Both 0 and 7 mean Sunday |
The same layout as the classic ASCII reference, for quick copy-paste:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, where 0 and 7 = Sunday)
│ │ │ │ │
* * * * *
The four special characters (plus Quartz extras)
Everything expressive about cron comes from four characters. Learn these and you can read almost any expression:
| Character | Name | Meaning | Example |
|---|---|---|---|
* | Asterisk | Every value for the field | * * * * * → every minute |
, | Comma | A list of specific values | 0,15,30,45 * * * * → every quarter hour |
- | Hyphen | An inclusive range | 0 9 * * 1-5 → 9 AM, Mon–Fri |
/ | Slash | A step (every nth value) | */5 * * * * → every 5 minutes |
Quartz and some Quartz-derived schedulers (including AWS EventBridge) add more: ? (no specific value, for the day fields), L (last — last day of month, or last given weekday), W (nearest weekday to a date), and # (the nth weekday of the month, e.g. 6#3 = the third Friday). These do not exist in standard Unix cron.
Common cron patterns (copy-paste)
| Expression | Runs |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes |
0 * * * * | Every hour, on the hour |
0 9 * * * | Every day at 9:00 AM |
0 9 * * 1-5 | Weekdays at 9:00 AM |
30 2 * * 6 | 2:30 AM every Saturday |
0 0 * * 0 | Every Sunday at midnight |
0 0 1 * * | Midnight on the 1st of every month |
0 */2 * * * | Every 2 hours |
0 8-18 * * 1-5 | Hourly, 8 AM–6 PM, weekdays |
Use our Cron Expression Builder below to construct and validate any of these visually — it translates the expression into plain English and shows the next few run times before you ship it.
Use our Cron Expression Builder to create and validate cron expressions on its own page as well.
Nonstandard shortcut strings (@daily, @reboot, and friends)
Vixie cron — the implementation on most Linux and BSD systems — adds @ macros that replace the five-field syntax for common schedules. They are more readable and harder to typo:
| Macro | Equivalent | Runs |
|---|---|---|
@yearly / @annually | 0 0 1 1 * | Once a year, Jan 1 at midnight |
@monthly | 0 0 1 * * | Midnight on the 1st |
@weekly | 0 0 * * 0 | Sunday at midnight |
@daily / @midnight | 0 0 * * * | Every day at midnight |
@hourly | 0 * * * * | Top of every hour |
@reboot | (no clock) | Once, when the cron daemon starts |
@reboot is the odd one out — it does not map to a time, it fires at startup. And support is not universal: system crontabs accept these macros, but Kubernetes CronJob and AWS EventBridge do not accept @reboot. When in doubt, use the explicit five-field form.
Cron expressions started on Unix systems but have evolved into a universal scheduling language. Whether you're building a Node.js web application, a Python data pipeline, a Java enterprise system, or deploying to Kubernetes, cron expressions provide the same elegant scheduling syntax—with a few platform-specific quirks to know.
For more on cron fundamentals, see our complete guide: What Is a Cron Expression?
Why Use Cron Expressions in Applications?
Before diving into specific platforms, it's worth understanding why cron-based scheduling has become the standard:
Language Independence: Once you learn cron syntax, you can apply it across any platform. Your knowledge transfers from Python to Node.js to Java to cloud services.
Declarative Scheduling: Instead of writing complex date-time logic with loops and conditions, you declare "when" with a simple string expression.
Battle-Tested: Cron has been scheduling tasks reliably since 1975. The libraries built on this foundation inherit decades of real-world testing.
Human Verification: Cron expressions can be visually verified and understood by team members, unlike procedural scheduling code.
Easy Configuration: Schedules can be stored in config files or environment variables, allowing schedule changes without code deployment.
Platform-Specific Implementations
While the core concept remains consistent, different platforms have adapted cron expressions to their needs. The single most important difference is how many fields each expects — paste a five-field Unix string into a six-field parser (or vice versa) and it will either error or, worse, run at the wrong time. Check this table before porting a schedule:
| Platform | Fields | Seconds field? | Notes |
|---|---|---|---|
Unix / Vixie cron, crontab | 5 | No | The baseline; smallest unit is 1 minute |
| Kubernetes CronJob | 5 | No | Macros supported; no @reboot |
| Google Cloud Scheduler | 5 | No | Standard five-field |
Spring @Scheduled | 6 | Yes | second minute hour day month weekday |
| Azure Functions (NCRONTAB) | 6 | Yes | Seconds first |
| AWS EventBridge | 6 | No | minute hour day month weekday year; uses ? |
| Quartz Scheduler | 6 or 7 | Yes | Seconds first, optional year last; adds ? L W # |
Now let's explore the most common implementations.
Node.js: Scheduling in JavaScript
Node.js has several excellent libraries for cron-based scheduling. The two most popular are node-cron and cron.
Using node-cron
The node-cron package provides a lightweight, pure JavaScript implementation:
const cron = require('node-cron');
// Every 5 minutes
cron.schedule('*/5 * * * *', () => {
console.log('Running health check');
performHealthCheck();
});
// Every weekday at 9 AM
cron.schedule('0 9 * * 1-5', () => {
console.log('Sending daily report');
generateAndSendReport();
});
// Every day at midnight
cron.schedule('0 0 * * *', () => {
console.log('Running database cleanup');
cleanupOldData();
});
Using the cron Package
The cron package offers more features and better control:
const { CronJob } = require('cron');
const job = new CronJob(
'0 */2 * * *', // Every 2 hours
function() {
console.log('Syncing data');
syncDataFromAPI();
},
null, // onComplete
true, // start immediately
'America/New_York' // timezone
);
// You can also control jobs programmatically
job.stop(); // Pause the job
job.start(); // Resume the job
Node.js Best Practices
Time Zones: Always specify a timezone explicitly, especially for applications serving multiple regions. Node.js cron libraries default to the system timezone, which can cause confusion in cloud environments.
Error Handling: Wrap your scheduled functions in try-catch blocks. A single unhandled error shouldn't crash your entire scheduling system.
cron.schedule('*/5 * * * *', async () => {
try {
await performTask();
} catch (error) {
logger.error('Scheduled task failed:', error);
notifyAdmins(error);
}
});
Graceful Shutdown: Stop cron jobs when your application shuts down to prevent orphaned tasks:
process.on('SIGTERM', () => {
job.stop();
process.exit(0);
});
Python: Flexible Scheduling Options
Python offers multiple approaches to cron-based scheduling, from simple scripts to sophisticated frameworks.
Using APScheduler
APScheduler (Advanced Python Scheduler) is the most feature-rich option:
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
scheduler = BlockingScheduler()
# Every 5 minutes
@scheduler.scheduled_job(CronTrigger.from_crontab('*/5 * * * *'))
def health_check():
print("Running health check")
perform_health_check()
# Every weekday at 9 AM
@scheduler.scheduled_job(CronTrigger.from_crontab('0 9 * * 1-5'))
def daily_report():
print("Generating daily report")
generate_and_send_report()
# Every day at midnight
scheduler.add_job(
cleanup_old_data,
CronTrigger.from_crontab('0 0 * * *'),
id='daily_cleanup'
)
scheduler.start()
Using python-crontab
For managing system-level cron jobs programmatically:
from crontab import CronTab
# Access user's crontab
cron = CronTab(user='username')
# Create a new cron job
job = cron.new(command='python /path/to/script.py')
job.setall('0 2 * * *') # Every day at 2 AM
job.enable()
# Write changes
cron.write()
# List all jobs
for job in cron:
print(job)
# Remove a job
cron.remove(job)
cron.write()
Using schedule (Simpler Alternative)
For lightweight needs, the schedule library uses cron-like syntax with Python readability:
import schedule
import time
def job():
print("Running scheduled task")
# While not pure cron syntax, it's cron-inspired
schedule.every(5).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("09:00").do(job)
schedule.every().monday.at("09:00").do(job)
while True:
schedule.run_pending()
time.sleep(1)
Python Best Practices
Long-Running Tasks: Use background schedulers (BackgroundScheduler) instead of blocking schedulers if your application does other work.
Persistence: APScheduler supports job stores (database, Redis) to persist scheduled jobs across application restarts.
Logging: Configure proper logging for scheduled tasks to debug timing issues:
import logging
logging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.DEBUG)
Java: Enterprise-Grade Scheduling
Java applications typically use Quartz Scheduler or Spring's built-in scheduling, both of which support cron expressions—with an important difference.
Quartz Scheduler
Quartz uses a six or seven-field format that includes seconds:
<second> <minute> <hour> <day-of-month> <month> <day-of-week> [year]
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class CronSchedulerExample {
public static void main(String[] args) throws Exception {
// Create scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// Define the job
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// Define the trigger with cron expression
// "0 */5 * * * ?" - Every 5 minutes (note the seconds and year fields)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0 */5 * * * ?")
)
.build();
// Schedule the job
scheduler.scheduleJob(job, trigger);
scheduler.start();
}
}
public class MyJob implements Job {
public void execute(JobExecutionContext context) {
System.out.println("Executing scheduled task");
}
}
Spring Framework @Scheduled
Spring provides annotation-based scheduling with cron support:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTasks {
// Every 5 minutes (Spring uses 6 fields: second, minute, hour, day, month, weekday)
@Scheduled(cron = "0 */5 * * * *")
public void healthCheck() {
System.out.println("Running health check");
performHealthCheck();
}
// Every weekday at 9 AM
@Scheduled(cron = "0 0 9 * * MON-FRI")
public void dailyReport() {
System.out.println("Generating daily report");
generateAndSendReport();
}
// First day of every month at midnight
@Scheduled(cron = "0 0 0 1 * *")
public void monthlyCleanup() {
System.out.println("Running monthly cleanup");
cleanupOldData();
}
}
Don't forget to enable scheduling in your Spring configuration:
@Configuration
@EnableScheduling
public class SchedulingConfig {
}
Java/Quartz Best Practices
Time Zones: Quartz supports timezone specification:
CronScheduleBuilder.cronSchedule("0 0 9 * * ?")
.inTimeZone(TimeZone.getTimeZone("America/New_York"))
Misfire Handling: Configure what happens if a job misses its scheduled time:
CronScheduleBuilder.cronSchedule("0 0 2 * * ?")
.withMisfireHandlingInstructionFireAndProceed()
Question Mark vs. Asterisk: In Quartz, use ? for "no specific value" in day-of-month or day-of-week when you want to specify the other. This avoids conflicts: 0 0 9 ? * MON (every Monday) vs. 0 0 9 1 * ? (first of month).
Kubernetes CronJobs
Kubernetes brings cron expressions to container orchestration:
apiVersion: batch/v1
kind: CronJob
metadata:
name: database-backup
spec:
schedule: "0 2 * * *" # Every day at 2 AM
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: backup-tool:latest
command: ["/bin/sh", "-c", "backup-database.sh"]
restartPolicy: OnFailure
Kubernetes CronJob Features
Concurrency Policy: Control what happens if a job is still running when the next execution time arrives:
spec:
schedule: "*/5 * * * *"
concurrencyPolicy: Forbid # Options: Allow, Forbid, Replace
Successful Jobs History: Keep recent job history for debugging:
spec:
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
Timezone Support (Kubernetes 1.24+):
spec:
schedule: "0 9 * * *"
timeZone: "America/New_York"
Cloud Platform Scheduling
AWS EventBridge (CloudWatch Events)
AWS uses a six-field cron format with some unique syntax:
cron(minute hour day-of-month month day-of-week year)
// AWS CDK example
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';
const rule = new events.Rule(this, 'Rule', {
schedule: events.Schedule.cron({
minute: '0',
hour: '9',
weekDay: 'MON-FRI'
})
});
rule.addTarget(new targets.LambdaFunction(myFunction));
AWS also supports rate expressions: rate(5 minutes) for simple intervals.
Google Cloud Scheduler
Google Cloud uses standard five-field cron expressions:
gcloud scheduler jobs create http daily-report \
--schedule="0 9 * * *" \
--uri="https://example.com/api/report" \
--http-method=POST \
--time-zone="America/New_York"
Azure Functions Timer Trigger
Azure uses six-field NCRONTAB expressions:
[FunctionName("DailyReport")]
public static void Run(
[TimerTrigger("0 0 9 * * 1-5")] TimerInfo myTimer,
ILogger log)
{
log.LogInformation($"Daily report function executed at: {DateTime.Now}");
GenerateReport();
}
Cross-Platform Best Practices
Always Specify Timezones: Different platforms handle timezones differently. Explicit timezone configuration prevents surprises, especially during daylight saving transitions.
Test Before Production: Use cron expression validators to verify your syntax produces the expected schedule across different platforms.
Monitor Execution: Log when tasks start, finish, and fail. Track execution duration to identify performance issues.
Handle Failures Gracefully: Implement retry logic, error notifications, and fallback mechanisms. Tasks will fail—plan for it.
Document Your Schedules: Add comments explaining why tasks run at specific times and what they do.
Version Control Schedules: Store cron configurations in version control alongside your code.
Consider Overlaps: If a task might run longer than the interval between executions, implement locking mechanisms to prevent concurrent runs.
Choosing the Right Approach
For Simple Applications: Use built-in language libraries (node-cron, APScheduler, @Scheduled).
For Distributed Systems: Use cloud-native schedulers (EventBridge, Cloud Scheduler) or orchestrators (Kubernetes CronJobs).
For Legacy Integration: Use system-level cron and script execution.
For Complex Workflows: Consider workflow engines like Apache Airflow (which also uses cron expressions) for task dependencies and orchestration.
Getting Started Quickly
Regardless of platform, start with our Cron Expression Builder to create and validate your expressions before implementing them. The tool provides plain English translations and shows upcoming execution times, helping you catch errors before deployment. Whether you're scheduling Node.js tasks, Python jobs, Java processes, or cloud functions, getting the cron expression right is the first step to reliable automation.