Cron Expression Guide: Syntax, Examples and Common Schedules
What is a Cron Expression?
A cron expression is a string that defines when a scheduled task should run. If you have ever needed to run a script "every day at 3 AM" or "every Monday at 9:30 AM", cron is the tool you reach for.
Cron has been around since the 1970s. It has not changed much because it does not need to — the 5-field expression system is compact, precise, and universally supported across Unix-like systems.
The 5-Field Syntax
A cron expression has 5 fields separated by spaces:
┬ ┬ ┬ ┬ ┬
│ │ │ │ └─ Day of Week (0-7, 0 and 7 = Sunday)
│ │ │ └────── Month (1-12)
│ │ └──────────── Day of Month (1-31)
│ └───────────────── Hour (0-23)
└────────────────────── Minute (0-59)Each field supports:
Common Cron Schedules
Here are patterns I use regularly:
# Every day at 3:00 AM (backup scripts, log rotation)
0 3 * * *
# Every hour (health checks, cache warming)
0 * * * *
# Every 5 minutes (high-frequency monitoring)
*/5 * * * *
# Every Monday at 9:00 AM (weekly reports)
0 9 * * 1
# First day of every month at midnight (monthly cleanup)
0 0 1 * *
# Every weekday at 6:00 PM (end-of-day tasks)
0 18 * * 1-5Setting Up a Cron Job
Cron jobs are managed through the crontab file. Each user has their own.
# Edit your crontab
crontab -e
# List your current cron jobs
crontab -l
# Remove all cron jobs
crontab -rThe crontab format adds six optional environment variable fields before the schedule:
# Example crontab entry
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
# Run backup script every day at 2:30 AM
30 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
# Clean temp files every hour
0 * * * * find /tmp -type f -mtime +1 -deleteSpecial Syntax: @reboot and Friends
Some cron implementations support @-strings for common schedules:
@reboot # Run once at startup
@daily # Run once a day (0 0 * * *)
@weekly # Run once a week (0 0 * * 0)
@monthly # Run once a month (0 0 1 * *)
@yearly # Run once a year (0 0 1 1 *)
@hourly # Run once an hour (0 * * * *)@reboot is particularly useful for starting services or daemons when a server restarts unexpectedly.
Cron in Docker Containers
Cron does not run inside Docker containers by default. You either install cron in the container or use the host cron to trigger docker exec:
# Host-side cron to run a container task
0 3 * * * docker exec my-container /usr/local/bin/backupAlternatively, use a dedicated cron container image that bundles cron:
FROM alpine:latest
RUN apk add --no-cache dcron
COPY crontab /var/spool/cron/crontabs/root
CMD ["crond", "-f", "-l", "2"]Logging and Debugging
Cron has a reputation for being hard to debug. A job fails silently and you only find out weeks later.
Two rules I follow:
1. Always redirect output to a log file. If you do not, cron sends output as email (which is often not configured).
# Bad: output disappears
30 2 * * * /home/user/scripts/backup.sh
# Good: output is logged
30 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&12. Use absolute paths. Cron runs with a minimal environment. Your script may work in your terminal and fail in cron because $PATH is different.
# Bad: may fail in cron
30 2 * * * python3 script.py
# Good: explicit paths
30 2 * * * /usr/bin/python3 /home/user/scripts/script.pyA Real Mistake
Last year I set up a cron job to renew an SSL certificate every 2 months. I wrote:
0 0 1 */2 * /usr/bin/certbot renewI thought "*/2" in the month field means "every 2 months". It does. But the day-of-month field is "1", so the job ran on the 1st of every 2nd month. The certificate expired on March 15th and the next run was April 1st. My site went down for two weeks while I was on vacation.
The fix: use a monitoring service to check certificate expiry, and set up a daily cron for cert renewal that only runs if renewal is needed (which is what certbot renew does by default — it checks before renewing).
Wrap Up
Cron is one of those Unix tools that looks simple on the surface but has enough edge cases to fill a book. Use absolute paths, log everything, and never assume your cron expression means what you think it does without testing it first with a cron expression parser.