Cron Jobs Explained: How to Schedule Tasks Like a Pro

17 Jun 2026 1,227 words

Cron Jobs Explained: How to Schedule Tasks Like a Pro

A cron job is a scheduled task that runs automatically on Unix-like operating systems. The cron daemon (crond) reads configuration files called crontabs and executes commands at the times specified by cron expressions. Cron is the backbone of server automation — it handles log rotation, backup scripts, email reports, cache clearing, and thousands of other recurring maintenance tasks without human intervention.

Crontab Syntax

A crontab entry consists of five time-and-date fields followed by the command to execute:

* * * * * /path/to/command
│ │ │ │ │
│ │ │ │ └─── 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 accepts:

  • Wildcard * — every valid value
  • Specific value — e.g., 5 means "at minute 5"
  • Range — e.g., 9-17 means "every hour from 9 to 17"
  • Step — e.g., */10 means "every 10 units"
  • List — e.g., 1,3,5 means "at 1, 3, and 5"
  • Combination — e.g., 9-17/2 means "every 2 hours from 9 to 17"

Common Cron Schedule Examples

* * * * *          → Every minute
*/5 * * * *        → Every 5 minutes
0 * * * *          → Every hour (at minute 0)
0 9 * * *          → Daily at 9:00 AM
0 9 * * 1-5        → Weekdays at 9:00 AM
0 9 * * 1          → Every Monday at 9:00 AM
0 0 1 * *          → First day of every month at midnight
0 */6 * * *        → Every 6 hours
30 8 * * 1,3,5     → Monday, Wednesday, Friday at 8:30 AM
0 0 * * 0          → Every Sunday at midnight
*/15 9-17 * * *    → Every 15 minutes during business hours
0 0 1 1 *          → Once a year (January 1st at midnight)

Shorthand Aliases

Some systems support named schedules:

@reboot     → Run once at system startup
@yearly     → 0 0 1 1 *
@monthly    → 0 0 1 * *
@weekly     → 0 0 * * 0
@daily      → 0 0 * * *
@hourly     → 0 * * * *

Managing Crontabs

# Edit your user's crontab
crontab -e

# List your crontab entries
crontab -l

# Remove your crontab
crontab -r

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

# System-wide crontab
/etc/crontab

# Drop-in directories
/etc/cron.d/          # Individual cron files
/etc/cron.hourly/     # Scripts run hourly
/etc/cron.daily/      # Scripts run daily
/etc/cron.weekly/     # Scripts run weekly
/etc/cron.monthly/    # Scripts run monthly

Real-World Cron Examples

Backup a Database Daily

# Create a backup script
cat > /usr/local/bin/backup-db.sh << 'SCRIPT'
#!/bin/bash
BACKUP_DIR="/var/backups/mysql"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mysqldump -u root my_database | gzip > "$BACKUP_DIR/db_$TIMESTAMP.sql.gz"
find "$BACKUP_DIR" -type f -mtime +30 -delete
SCRIPT

chmod 755 /usr/local/bin/backup-db.sh

# Schedule it — runs daily at 2:00 AM
# crontab entry:
0 2 * * * /usr/local/bin/backup-db.sh

Rotate Application Logs

# Archive and compress logs older than 7 days
0 3 * * 0 find /var/log/myapp -name "*.log" -mtime +7 -exec gzip {} \;

Check Disk Space and Send Alert

# Check disk usage every hour during business hours
0 9-18 * * 1-5 df -h / | awk 'NR==2 {if ($5+0 > 80) print "Disk space critical: " $5}' | mail -s "Disk Alert" admin@example.com

Clear Cache Every 6 Hours

# Clear application cache
0 */6 * * * curl -s https://example.com/clear-cache > /dev/null 2>&1

Logging and Output Handling

By default, cron sends any output (stdout and stderr) to the user's local mail. On most servers, local mail is not configured, which causes undelivered messages to accumulate or be silently dropped.

# Redirect stdout to a log file
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# Discard all output (silent cron)
0 2 * * * /usr/local/bin/backup.sh > /dev/null 2>&1

# Separate stdout and stderr
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>> /var/log/backup.error.log

Always redirect output in production cron jobs. Unredirected output fills the mail spool and wastes disk space.

Environment Variables in Crontab

Cron runs with a minimal environment — typically PATH=/usr/bin:/bin, HOME set to the user's home directory, and no shell profile is sourced. This is the source of many cron bugs.

# Set environment variables in crontab
MAILTO=admin@example.com
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash

0 2 * * * /usr/local/bin/backup.sh

If your script depends on environment variables defined in .bashrc or .profile, source them explicitly:

0 2 * * * source $HOME/.bashrc && /usr/local/bin/backup.sh

Better yet, define all required variables inside the script itself:

#!/bin/bash
export PATH="/usr/local/bin:/usr/bin:/bin"
export NODE_ENV="production"
# ... script logic ...

Cron Best Practices

  • Use absolute paths — Never rely on relative paths in cron commands
  • Always redirect output — Append >> /var/log/job.log 2>&1 to every cron entry
  • Set PATH explicitly — Either in crontab or inside the script
  • Test the command manually — Run the exact command in a shell before adding it to crontab
  • Use lock files for long-running jobs — Prevent overlapping executions
  • Add monitoring — Check that critical cron jobs ran successfully
  • Use scripts, not inline commands — Put complex logic in a script file and reference it from crontab

Lock File Pattern

Prevent a cron job from running if the previous instance is still executing:

#!/bin/bash
LOCKFILE="/tmp/backup.lock"

if [ -f "$LOCKFILE" ]; then
    echo "Previous instance still running, exiting"
    exit 1
fi

trap "rm -f $LOCKFILE" EXIT
touch "$LOCKFILE"

# Job logic here

Common Pitfalls

Pitfall 1: Percent signs need escaping

In crontab, % has special meaning (it indicates a newline in the mail body). Escape it with a backslash:

# ❌ Wrong
0 2 * * * date +%Y%m%d

# ✅ Correct
0 2 * * * date +\%Y\%m\%d

# Better — put the date command in a script
0 2 * * * /usr/local/bin/daily-report.sh

Pitfall 2: Cron does not source your shell profile

# ❌ Wrong — assumes NVM or NODE_PATH is set
0 2 * * * node /home/user/app/script.js

# ✅ Correct — use absolute path and explicit env
0 2 * * * export PATH="/usr/local/bin:/usr/bin:/home/user/.nvm/versions/node/v18/bin:$PATH" && node /home/user/app/script.js

Pitfall 3: Overlapping jobs

If a job runs longer than its interval, two instances run simultaneously. Use a lock file or flock:

# Use flock to prevent overlap
*/5 * * * * /usr/bin/flock -n /tmp/myjob.lock /usr/local/bin/myjob.sh

Online Tools

The Cron Job Command Generator tool on Help2Code provides an interactive form with preset schedules (every minute, hourly, daily, weekly, monthly) and custom cron field inputs. Configure the command, output handling, and copy the generated crontab line. The Cron Expression Parser tool helps you decode existing cron expressions and understand when they will execute.

Conclusion

Cron is one of the most essential tools for server administration and automation. Master the five-field syntax, always handle output explicitly, set environment variables, and test commands before scheduling. Use the Cron Job Command Generator to build crontab entries quickly and the Cron Expression Parser to verify existing schedules.


About this article

Learn how cron jobs work in Linux, how to write crontab syntax, schedule recurring tasks, and avoid common cron pitfalls with real-world examples.


Related Articles


Related Tools

Help2Code Logo
Menu