Don't like ads? Go Ad-Free Today

Cron Expressions A Practical Reference With Real Examples

Published on
Cron Expressions: A Practical Reference With Real Examples 1
ADVERTISEMENT · REMOVE?

A cron expression is five space-separated fields that tell a Unix scheduler when to run a command. Five fields, a handful of special characters, and a few common patterns — that is the entire mental model. This reference covers the syntax, the characters that trip people up, and the schedules developers actually reach for.

The Five Fields

Standard cron uses five positional fields:

* * * * *
│ │ │ │ └─ Day of week   (0–7, Sunday = 0 or 7)
│ │ │ └─── Month         (1–12)
│ │ └───── Day of month  (1–31)
│ └─────── Hour          (0–23)
└───────── Minute        (0–59)

AWS EventBridge and Java’s Quartz scheduler add a seconds field at the front, making it six fields total. Every other field shifts right. This trips up developers moving between environments — a Quartz expression pasted into a standard crontab will run on the wrong schedule without any warning.

Stick to five-field POSIX cron unless your platform explicitly requires six.

Special Characters

CharacterMeaningExample
*Any value — match every unit* * * * * — every minute
,List of values0 9,17 * * * — at 9am and 5pm
-Range0 9-17 * * * — every hour 9am to 5pm
/Step interval*/15 * * * * — every 15 minutes
?No specific value (Quartz/AWS only)0 0 15 * ? — 15th of each month, any weekday
LLast (Quartz/AWS only)0 0 L * ? — last day of each month
WNearest weekday (Quartz/AWS only)0 0 15W * ? — nearest weekday to the 15th

Standard crontab only recognises *, ,, -, and /. If you see ?, L, or W in an expression, it was written for Quartz or AWS EventBridge — don’t paste it into a Linux crontab unchanged.

The Reference Table: Schedules Developers Actually Use

This is the part worth bookmarking. Build and validate any of these expressions with the IO Tools Cron Expression Generator.

DescriptionCron ExpressionNotes
Every minute* * * * *Rarely appropriate in production
Every 5 minutes*/5 * * * *Health checks, short polling cycles
Every 15 minutes*/15 * * * *Cache warm-ups, feed syncs
Every 30 minutes*/30 * * * *Equivalent to 0,30 * * * *
Every hour (on the hour)0 * * * *Runs at :00 of every hour
Every 6 hours0 */6 * * *Data sync, incremental exports
Daily at midnight UTC0 0 * * *Standard daily batch trigger
Daily at 9am UTC0 9 * * *Morning report generation
Weekdays at 9am UTC0 9 * * 1-5Business-hours-only jobs (Mon–Fri)
Weekdays at 8:30am UTC30 8 * * 1-5Pre-standup report delivery
Every Sunday at 2am0 2 * * 0Weekly maintenance, off-peak backups
First day of each month0 0 1 * *Monthly billing runs, recurring reports
January 1st at midnight0 0 1 1 *Annual resets, year-start jobs

The Timezone Gotcha

Cron has no timezone awareness. It runs in whatever timezone the server is configured for — on most Linux systems, that is UTC. This is usually fine until you have jobs tied to business hours, or users in multiple regions wondering why the “9am report” arrives at 2pm.

The safest defaults:

  • Set your server to UTC. Convert to local time in application logic, not in the cron schedule.
  • Comment every cron job with the effective local time, so the next person reading the crontab isn’t guessing.
  • When using cloud schedulers (AWS EventBridge, Google Cloud Scheduler), verify the timezone field — most support IANA timezone names directly, which removes the ambiguity.
# Always comment with the effective local time
# Runs daily at midnight UTC (= 8pm EST / 5pm PST)
0 0 * * * /usr/bin/python3 /opt/scripts/daily_report.py

Testing: Calculate Next Runs Before You Deploy

Deploying a cron job to discover it fires every minute instead of every hour is a rite of passage. Skip it.

The IO Tools Cron Next Run Calculator shows exactly when your expression will fire next — paste your expression and get the next ten run times before touching a server.

For command-line validation:

# Install croniter (Python) for quick expression testing
pip install croniter

python3 -c "
from croniter import croniter
from datetime import datetime

cron = croniter('*/15 * * * *', datetime.utcnow())
for _ in range(5):
    print(cron.get_next(datetime))
"

Adding a Cron Job on Linux

# Open the crontab editor for the current user
crontab -e

# Format: minute hour day month weekday command
# Run backup script daily at 2:30am UTC
30 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1

# Run a Python script every 5 minutes
*/5 * * * * /usr/bin/python3 /home/user/scripts/sync.py

# View current crontab entries
crontab -l

# Edit another user's crontab (requires root)
crontab -u www-data -e

The 2>&1 at the end of the backup line redirects stderr into stdout, so both go into the log file. Without it, cron errors go to the mail spool — and nobody checks that.

GitHub Actions Scheduled Workflow

GitHub Actions uses the same five-field cron syntax, always in UTC. There is no timezone override.

name: Nightly Data Export

on:
  schedule:
    # Runs at 1:00 AM UTC every weekday
    - cron: "0 1 * * 1-5"
  workflow_dispatch: # Allow manual trigger

jobs:
  export:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run export script
        run: python scripts/export.py

One caveat: GitHub Actions scheduled workflows can be delayed up to 15 minutes during high-load periods. Don’t rely on them for anything requiring precise timing.

When Cron Isn’t Enough

Standard cron handles most use cases on a single server. Its limits become problems at scale:

  • No retry on failure. If the job crashes, the next run is the next scheduled time — there’s no automatic retry.
  • No distributed locking. Multiple servers running the same crontab will fire the same job simultaneously.
  • No observability. There’s no built-in dashboard for run history, failure alerts, or duration tracking.
ProblemBetter Alternative
Retry logic and task queuesCelery Beat (Python), Sidekiq-Cron (Ruby)
Cloud-native scheduling with retriesAWS EventBridge + Lambda, Google Cloud Scheduler
CI/CD pipeline triggersGitHub Actions schedules
Observable job orchestrationAirflow, Prefect, Temporal

For scripts on a single server, cron is still the right tool — it’s simple, reliable, and has zero dependencies. For anything that needs retry guarantees, distributed execution, or failure visibility, a dedicated task queue pays for itself quickly.

Use the Cron Expression Generator to build your next schedule without memorising the syntax, and the Cron Next Run Calculator to verify it fires when you expect.

Want To enjoy an ad-free experience? Go Ad-Free Today

Install Our Extensions

Add IO tools to your favorite browser for instant access and faster searching

Add to Chrome Extension Add to Edge Extension Add to Firefox Extension Add to Opera Extension

Scoreboard Has Arrived!

Scoreboard is a fun way to keep track of your games, all data is stored in your browser. More features are coming soon!

ADVERTISEMENT · REMOVE?
ADVERTISEMENT · REMOVE?
ADVERTISEMENT · REMOVE?

News Corner w/ Tech Highlights

Get Involved

Help us continue providing valuable free tools

Buy me a coffee
ADVERTISEMENT · REMOVE?