What Is Cron?

Cron is a time-based job scheduler built into Unix-like operating systems. It runs commands or scripts automatically at specified intervals — every minute, every night at 2am, on the first of every month, or on any schedule you define. Nearly every server-side developer encounters cron eventually: database backups, cache clearing, report generation, REST API, SSL certificate renewal — all common cron use cases.

Despite being decades old, cron is still the most reliable way to schedule tasks on Linux servers. Understanding it properly saves significant debugging time.

The Crontab Format

Cron schedules are defined in a crontab file with a specific five-field syntax:

# ┌─────────── minute (0–59)
# │ ┌───────── hour (0–23)
# │ │ ┌─────── day of month (1–31)
# │ │ │ ┌───── month (1–12 or JAN–DEC)
# │ │ │ │ ┌─── day of week (0–6, 0=Sunday, or SUN–SAT)
# │ │ │ │ │
# * * * * * command to execute

Each field accepts a specific value, a range (1-5), a list (1,3,5), a step (*/15), or a wildcard (* = every).

Common Scheduling Patterns

# Every minute
* * * * * /usr/bin/python3 /scripts/check.py

# Every 15 minutes
*/15 * * * * /scripts/sync.sh

# Every day at 2:30am
30 2 * * * /scripts/backup.sh

# Every Monday at 9am
0 9 * * 1 /scripts/weekly-report.sh

# First day of every month at midnight
0 0 1 * * /scripts/monthly-invoice.sh

# Every weekday (Mon–Fri) at 8am
0 8 * * 1-5 /scripts/business-hours-task.sh

# Every 6 hours
0 */6 * * * /scripts/cache-clear.sh

Building complex expressions from scratch is error-prone. The Cron Expression Generator lets you select your schedule visually and shows the next 5 run times — a much safer way to verify your expression before deploying it.

Managing Crontabs

# Edit your crontab (opens in default editor)
crontab -e

# List your current crontab
crontab -l

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

# System-wide cron jobs (in /etc/cron.d/)
ls /etc/cron.d/
ls /etc/cron.daily/   # Scripts here run daily via run-parts

Why Cron Jobs Fail Silently (and How to Fix It)

Cron jobs failing silently is the most common frustration. The script works perfectly when you run it manually, but nothing happens on schedule. The usual culprits:

1. Environment variables

Cron runs with a minimal environment — no PATH, no HOME, no virtual environments. Always use absolute paths:

# Wrong — relies on PATH
* * * * * python3 myscript.py

# Correct — absolute paths
* * * * * /usr/bin/python3 /home/user/scripts/myscript.py

# Or set PATH at the top of your crontab
PATH=/usr/local/bin:/usr/bin:/bin
* * * * * python3 /home/user/scripts/myscript.py

2. No output capture

By default, cron emails output to the local system user. On most servers this goes nowhere. Redirect output to a log file:

# Capture both stdout and stderr
30 2 * * * /scripts/backup.sh >> /var/log/backup.log 2>&1

# Suppress all output (only do this for well-tested scripts)
30 2 * * * /scripts/backup.sh > /dev/null 2>&1

3. Working directory assumptions

Cron doesn't cd to your script's directory. If your script uses relative paths, they'll break:

# Explicitly set the working directory
30 2 * * * cd /var/www/myapp && /usr/bin/php artisan schedule:run

4. File permissions

The script must be executable by the user running cron:

chmod +x /scripts/backup.sh

Logging and Monitoring

For production cron jobs, implement proper logging and alerting:

#!/bin/bash
# backup.sh with logging
LOG="/var/log/backup.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting backup" >> "$LOG"

# ... backup commands ...

if [ $? -eq 0 ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup completed successfully" >> "$LOG"
else
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: Backup failed" >> "$LOG"
    # Send alert email
    echo "Backup failed on $(hostname)" | mail -s "CRON ALERT" admin@example.com
fi

Cron Alternatives Worth Knowing

  • systemd timers — more powerful than cron, with dependency management and better logging via journald
  • Laravel Scheduler / Django-cron — framework-level schedulers that use a single cron entry (* * * * *) and manage schedules in code
  • Celery Beat — for Python applications needing distributed task scheduling

For most simple server tasks, plain cron is still the right tool. Keep schedules in version control, use the Cron Expression Generator to verify your timing, log everything, and test your scripts manually before scheduling them.