Web Development

What Is a Cron Expression? Syntax Guide for Every Platform

What is a cron expression? Learn cron syntax with examples for Node.js, Python, Java, Kubernetes, and cloud platforms. Master the 5-field format to schedule any task.

By Inventive HQ Team

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:

The five fields of a standard cron expression Five labelled boxes — minute, hour, day of month, month, and day of week — each showing its allowed range, with a highlight sweeping across them one at a time. Standard cron: five space-separated fields * Minute 0 – 59 * Hour 0 – 23 * Day of month 1 – 31 * Month 1 – 12 * Day of week 0 – 7 (Sun) * * * * * An asterisk in a field means "every value" — five asterisks means "every minute"
#FieldAllowed valuesNotes
1Minute0–59Smallest unit in standard cron
2Hour0–2324-hour clock
3Day of month1–31
4Month1–12 or JAN–DEC
5Day of week0–7 or SUN–SATBoth 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:

CharacterNameMeaningExample
*AsteriskEvery value for the field* * * * * → every minute
,CommaA list of specific values0,15,30,45 * * * * → every quarter hour
-HyphenAn inclusive range0 9 * * 1-5 → 9 AM, Mon–Fri
/SlashA 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)

ExpressionRuns
* * * * *Every minute
*/5 * * * *Every 5 minutes
0 * * * *Every hour, on the hour
0 9 * * *Every day at 9:00 AM
0 9 * * 1-5Weekdays at 9:00 AM
30 2 * * 62:30 AM every Saturday
0 0 * * 0Every Sunday at midnight
0 0 1 * *Midnight on the 1st of every month
0 */2 * * *Every 2 hours
0 8-18 * * 1-5Hourly, 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.

Loading interactive tool...

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:

MacroEquivalentRuns
@yearly / @annually0 0 1 1 *Once a year, Jan 1 at midnight
@monthly0 0 1 * *Midnight on the 1st
@weekly0 0 * * 0Sunday at midnight
@daily / @midnight0 0 * * *Every day at midnight
@hourly0 * * * *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:

PlatformFieldsSeconds field?Notes
Unix / Vixie cron, crontab5NoThe baseline; smallest unit is 1 minute
Kubernetes CronJob5NoMacros supported; no @reboot
Google Cloud Scheduler5NoStandard five-field
Spring @Scheduled6Yessecond minute hour day month weekday
Azure Functions (NCRONTAB)6YesSeconds first
AWS EventBridge6Nominute hour day month weekday year; uses ?
Quartz Scheduler6 or 7YesSeconds 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();
});
Advertisement

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.

Frequently Asked Questions

What is a cron expression and how does it work?

A cron expression is a string of five fields — minute, hour, day of month, month, and day of week — that tells a scheduler when to run a task. A scheduler checks the expression once a minute; when the current time matches every field, the job fires. For example, 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)" — so it runs at 9:00 AM Monday through Friday. The five-field format originated in Unix cron and is now used, with minor variations, across Node.js, Python, Kubernetes, and most cloud schedulers.

How many fields are in a cron expression?

Standard Unix cron uses five fields: minute, hour, day of month, month, and day of week. Some systems add a seconds field at the front to make six — Spring's @Scheduled and Azure Functions NCRONTAB both do this. Quartz Scheduler (used in Java) uses six fields and adds an optional seventh year field, so it accepts six or seven. AWS EventBridge uses six fields (minute through year) but has no seconds. The count matters: the same string can mean different times on different platforms, so always confirm how many fields your scheduler expects.

What do the special characters mean in a cron expression?

Four characters do the heavy lifting. An asterisk (*) means "every value" for that field. A comma (,) lists specific values, so 1,15,30 in the minute field runs at those three minutes. A hyphen (-) defines an inclusive range, so 1-5 in the day-of-week field means Monday through Friday. A forward slash (/) sets a step, so */15 in the minute field runs every 15 minutes (at :00, :15, :30, :45). Quartz and some other schedulers add ? (no specific value), L (last), W (nearest weekday), and # (nth weekday of the month).

What does */5 * * * * mean in cron?

*/5 * * * * runs a task every 5 minutes. The */5 in the minute field is a step value meaning "every 5th minute" — it fires at :00, :05, :10, :15, and so on through :55. The four asterisks that follow mean every hour, every day of the month, every month, and every day of the week, so there is no further restriction. It is one of the most common cron expressions, typically used for health checks, polling, and short-interval sync jobs.

What are @yearly, @daily, and @reboot in cron?

They are nonstandard shortcut strings added by Vixie cron (the implementation on most Linux and BSD systems) that replace the five-field syntax for common schedules. @yearly (or @annually) equals 0 0 1 1 *, @monthly equals 0 0 1 * *, @weekly equals 0 0 * * 0, @daily (or @midnight) equals 0 0 * * *, and @hourly equals 0 * * * *. @reboot is special — it runs once when the cron daemon starts, not on a recurring clock. These macros are widely supported in system crontabs but not everywhere: Kubernetes CronJob and AWS EventBridge do not accept @reboot.

Why does Quartz use six or seven fields instead of five?

Quartz Scheduler was designed for enterprise Java scheduling where second-level precision and year targeting are useful, so it added a seconds field at the front (making six) and an optional year field at the end (making seven). A Quartz expression like 0 0 9 ? * MON reads: second 0, minute 0, hour 9, any day of month, any month, Monday. Because Quartz's day-of-week field is 1-7 (where 1 = Sunday) rather than Unix's 0-6, and because it requires ? in one of the two day fields, a Unix cron string will not run correctly in Quartz without adjustment.

What is the difference between ? and * in a cron expression?

This distinction only exists in Quartz and a few Quartz-derived schedulers (like AWS EventBridge), not in standard Unix cron. An asterisk (*) means "every value." A question mark (?) means "no specific value" and is only allowed in the day-of-month and day-of-week fields. You use ? when you want to specify one of those two fields but leave the other unconstrained, because setting both to a real value would conflict. For example, 0 0 9 10 * ? fires on the 10th of the month regardless of weekday, while 0 0 9 ? * MON fires every Monday regardless of date.

Does the day-of-week field start at 0 or 1?

In standard Unix and Vixie cron the day-of-week field is 0-7, where both 0 and 7 mean Sunday, and you can also use three-letter names (SUN-SAT). Quartz breaks from this: its day-of-week field is 1-7 where 1 means Sunday and 7 means Saturday. This off-by-one difference is a common source of bugs when porting a schedule from a Linux crontab to a Java Quartz trigger, so always verify which convention your scheduler uses.

Do cron expressions support seconds?

Standard Unix cron does not — its smallest unit is one minute, because the daemon evaluates schedules once per minute. To run something more often than once a minute with system cron you need a workaround (such as a loop with sleep). Schedulers that add a seconds field — Quartz, Spring's @Scheduled, and Azure Functions NCRONTAB — can fire at sub-minute intervals, for example 0/30 * * * * * every 30 seconds in Quartz. If you need second-level scheduling, choose a platform whose cron format includes the seconds field.

cron expressionwhat is cron expressioncron syntaxtask schedulingautomationcron