Cron Jobs: The Unsung Hero of Automation
By The IT Hustle Team
This article was generated with AI assistance and reviewed by our team for accuracy and quality. All technical information and examples have been verified.
Somewhere right now, a server is quietly running a backup. Another is rotating logs before the disk fills up. A third is generating a report and emailing it to a manager who has no idea it's automated. All of these things happen because of one of the oldest, most reliable pieces of software in the Unix ecosystem: cron.
Cron has been scheduling tasks on Unix systems since the 1970s. It predates the web, predates Linux, predates most of the technology stacks we argue about on the internet. And yet it remains one of the most important tools in any system administrator's toolkit. If you manage servers, automate workflows, or just want your computer to do things while you sleep, you need to understand cron.
This isn't a toy. This is the backbone of operational automation for millions of systems worldwide. Let's break it down completely.
What Is Cron, Exactly?
Cron is a time-based job scheduler found on virtually every Unix-like operating system — Linux, macOS, FreeBSD, you name it. It runs as a daemon (a background process) and checks a schedule file called the crontab (cron table) every minute. If the current time matches a scheduled entry, cron executes the associated command.
That's it. No fancy dashboard, no web UI, no subscription fee. Just a text file and a daemon that's been doing its job reliably for over 50 years. There's a lesson in that simplicity.
Every user on a system can have their own crontab, edited with crontab -e. There's also a system-wide crontab at /etc/crontab and directory-based scheduling in /etc/cron.d/, /etc/cron.daily/, /etc/cron.hourly/, and so on.
Cron Syntax: The Five Fields
The cron syntax looks cryptic at first glance, but once you understand the five fields, it becomes second nature. Every cron expression consists of five time fields followed by the command to execute:
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12)
│ │ │ │ ┌───────────── day of week (0–7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * * command_to_execute
Each field can contain a single value, a range, a list, a step value, or a wildcard. Here's what each special character means:
- * — matches every possible value for that field
- , — separates multiple values (e.g., 1,3,5)
- - — defines a range (e.g., 1-5 means Monday through Friday)
- / — defines a step value (e.g., */5 means every 5 units)
Common Cron Schedules
Let's walk through the schedules you'll use most often:
* * * * * /path/to/script.sh
# Every 5 minutes
*/5 * * * * /path/to/script.sh
# Every hour at minute 0
0 * * * * /path/to/script.sh
# Every day at 2:30 AM
30 2 * * * /path/to/script.sh
# Every Monday at 9:00 AM
0 9 * * 1 /path/to/script.sh
# First day of every month at midnight
0 0 1 * * /path/to/script.sh
# Every weekday at 6:00 PM
0 18 * * 1-5 /path/to/script.sh
# Every 15 minutes during business hours
*/15 9-17 * * 1-5 /path/to/script.sh
# Twice a day at 8 AM and 8 PM
0 8,20 * * * /path/to/script.sh
# Every Sunday at 3 AM (weekly maintenance)
0 3 * * 0 /path/to/script.sh
If you want to build and validate cron expressions without memorizing the syntax, use our Cron Expression Builder — it generates cron syntax in real time as you select your schedule.
Real-World Use Cases
Cron isn't just an academic concept. It powers critical infrastructure across every industry. Here are the patterns you'll encounter constantly:
1. Automated Backups
The most common cron use case. A nightly backup script that dumps your database, compresses it, and uploads it to cloud storage:
0 2 * * * /opt/scripts/backup-db.sh >> /var/log/backup.log 2>&1
Notice the >> /var/log/backup.log 2>&1 at the end. This redirects both standard output and standard error to a log file. Without this, cron will try to email the output to the user — and if your mail system isn't configured, that output disappears into the void. Always redirect output in cron jobs.
2. Log Rotation
Logs grow forever if you let them. Cron can compress, archive, and delete old logs on a schedule. While most modern systems use logrotate (which is itself triggered by cron), you might have application-specific logs that need custom handling:
0 0 * * 0 /opt/scripts/rotate-app-logs.sh
3. Health Checks and Monitoring
Before the era of sophisticated monitoring tools like Datadog and Prometheus, cron jobs were (and still are) the simplest way to check if services are running and alert when they're not:
*/5 * * * * curl -sf http://localhost:8080/health || /opt/scripts/alert.sh "Web server down"
4. Report Generation
Managers love daily and weekly reports. Rather than generating them on demand (slow, resource-intensive), cron can pre-generate them during off-hours:
0 6 * * 1-5 /opt/scripts/generate-sales-report.sh
# Weekly summary every Friday at 5 PM
0 17 * * 5 /opt/scripts/weekly-summary.sh
5. Cache Warming and Cleanup
Applications generate temporary files, cache data, and session files that need periodic cleanup. Cron handles this silently:
0 3 * * * find /tmp/app-cache -type f -mtime +7 -delete
# Warm the API cache every morning at 5:30 AM
30 5 * * * /opt/scripts/warm-cache.sh
Common Pitfalls That Will Ruin Your Day
Cron is simple, but that simplicity hides some sharp edges. These are the problems that bite everyone at least once:
The PATH Problem
This is the number one cause of "it works in my terminal but not in cron." When cron executes a command, it uses a minimal environment. Your shell's PATH variable — the one that knows where node, python3, docker, and all your other tools live — does not exist in cron's environment.
Why it matters:
A script that runs perfectly when you type ./backup.sh in your terminal might fail silently in cron because it can't find pg_dump, aws, or whatever binary your script calls. The fix is to either use absolute paths in your scripts or set PATH explicitly at the top of your crontab:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Or use absolute paths in commands
0 2 * * * /usr/bin/pg_dump mydb | /usr/bin/gzip > /backups/db.sql.gz
Timezone Confusion
Cron uses the system's timezone by default. If your server is in UTC (as most cloud servers are) but you're thinking in Eastern Time, your "2 AM backup" might run at 10 PM or 7 AM depending on daylight saving time. Always know what timezone your server is set to:
timedatectl
# Or check the TZ environment variable
echo $TZ
# Some cron implementations support CRON_TZ
CRON_TZ=America/New_York
0 2 * * * /opt/scripts/backup.sh
Daylight saving time causes another subtle issue: when clocks spring forward, the 2 AM hour doesn't exist, so a job scheduled for 2:30 AM won't run. When clocks fall back, the 1 AM hour happens twice, and the job might run twice. Schedule critical jobs for times that aren't affected by DST transitions, or just use UTC everywhere.
Overlapping Runs
If a cron job takes longer to complete than the interval between runs, you'll get overlapping instances. A backup script that takes 20 minutes, scheduled every 15 minutes, means you'll have multiple backups running simultaneously — fighting over the same files, overloading the database, and potentially corrupting data.
The classic solution is a lock file:
LOCKFILE=/tmp/backup.lock
if [ -f "$LOCKFILE" ]; then
echo "Backup already running, exiting"
exit 0
fi
trap "rm -f $LOCKFILE" EXIT
touch "$LOCKFILE"
# Your actual backup logic here
/usr/bin/pg_dump mydb | gzip > /backups/db-$(date +%Y%m%d).sql.gz
Or use flock, which is more robust:
*/15 * * * * /usr/bin/flock -n /tmp/backup.lock /opt/scripts/backup.sh
Silent Failures
By default, cron tries to mail output to the user. On most modern systems, local mail isn't configured, so output and errors just vanish. Your cron job has been failing for three months and nobody noticed. Always redirect output to a log file, and consider adding alerting:
0 2 * * * /opt/scripts/backup.sh >> /var/log/cron-backup.log 2>&1
# Better: log with timestamps
0 2 * * * /opt/scripts/backup.sh 2>&1 | while read line; do echo "$(date): $line"; done >> /var/log/cron-backup.log
# Best: log AND alert on failure
0 2 * * * /opt/scripts/backup.sh >> /var/log/cron-backup.log 2>&1 || /opt/scripts/alert.sh "Backup failed"
Cron Alternatives: systemd Timers
On modern Linux systems running systemd, there's an alternative to cron: systemd timers. They offer some advantages — better logging via journalctl, dependency management, resource controls via cgroups, and more precise scheduling options including randomized delays to prevent thundering herd problems.
However, systemd timers require creating two files (a .timer unit and a .service unit) for every scheduled task, compared to a single line in a crontab. For most tasks, that's overkill. Use systemd timers when you need their advanced features. Use cron when you just need something to run at a specific time. There's no shame in choosing simplicity.
Debugging Cron Jobs
When a cron job isn't working, follow this debugging checklist:
- Check that the cron daemon is running:
systemctl status cronorps aux | grep cron - Verify your crontab is saved:
crontab -l - Check system logs:
grep CRON /var/log/syslogorjournalctl -u cron - Test the command manually as the same user cron runs as
- Check file permissions on the script (must be executable)
- Verify the PATH includes all needed binaries
- Look for environment variable dependencies that exist in your shell but not in cron
- Check if the output is being redirected somewhere you're not looking
- Make sure there are no percent signs (
%) in your command — cron treats them as newlines unless escaped with a backslash
That last one about percent signs catches people all the time. The command date +%Y%m%d will break in cron because the % characters get interpreted. You need to escape them: date +\%Y\%m\%d, or put the command in a script and call the script instead.
Security Considerations
Cron jobs run with the permissions of the user who owns the crontab. This means:
- Never put passwords or API keys directly in crontab entries — use environment files or secrets managers
- Restrict who can use cron with
/etc/cron.allowand/etc/cron.deny - Audit cron jobs regularly — attackers love planting persistence via crontabs
- Don't run cron jobs as root unless absolutely necessary
- Scripts called by cron should have restrictive permissions (750 or 700)
- Validate and sanitize any external input your cron scripts process
One security pattern worth adopting: have your cron script source its credentials from a read-protected file rather than embedding them anywhere in the crontab or the script itself:
source /etc/app-secrets/backup.env # owned by root, mode 600
/usr/bin/pg_dump "postgres://$DB_USER:$DB_PASS@$DB_HOST/$DB_NAME" | gzip > /backups/db.sql.gz
Managing Crontabs Like a Professional
As you accumulate cron jobs, maintainability becomes critical. Here are some best practices:
- Comment every cron entry with what it does and who added it
- Group related jobs together with section headers
- Version control your crontabs — export them with
crontab -l > crontab.bakand check them into git - Use wrapper scripts rather than inline commands for anything beyond a single simple command
- Include a MAILTO line at the top to control where error notifications go
- Document the expected runtime of each job to detect performance degradation
Cron has survived for over five decades because it solves a fundamental problem simply and reliably. You don't need Kubernetes CronJobs, Airflow, or a managed scheduler for most automation tasks. You need a text file and a daemon that checks the clock every minute. Master cron, and you've mastered one of the most practical skills in system administration.
If you're building cron expressions and want to verify them before deploying, try the Cron Expression Builder. It translates your schedule into plain English so you can confirm it does what you think it does.
Cron doesn't need a marketing team. It just runs. Every minute of every day, on millions of systems, it checks the clock and does its job. If only everything in tech were that dependable. Build your cron expressions with confidence — try the Cron Expression Builder.
We build free developer tools and write about AI, automation, and developer productivity. 30 tools, 33 articles, and an AI Prompt Engine — all built to help workers navigate the AI era. Published by Salty Rantz LLC.
The IT Hustle Weekly
What changed in AI this week and what it means for your job. Free tools, honest reviews, zero spam.
Generate Your Own Anti-Hallucination Prompts
Our AI Prompt Engine uses patent-pending technology to generate prompts with built-in verification and contradiction testing.
Try 3 Free Generations →