What Is a Cron Job?

A cron job is a scheduled task managed by the cron daemon — a background service that runs continuously on Linux and Unix-based systems. The name comes from the Greek word chronos (time). Cron reads a configuration file called a crontab (cron table) that lists tasks and when to run them, then executes them automatically at the right time.

Cron is the go-to tool for:

  • Running Python or Bash scripts on a schedule (backups, scrapers, reports)
  • Clearing temporary files and logs periodically
  • Sending automated emails or notifications
  • Pulling data from APIs every hour or every morning
  • Restarting services or checking server health at intervals
  • Running database cleanup queries nightly
💡

Is cron available on my server? Cron comes pre-installed on virtually every Linux distribution — Ubuntu, Debian, CentOS, AlmaLinux, Rocky Linux and more. Check it is running with: systemctl status cron (Debian/Ubuntu) or systemctl status crond (CentOS/RHEL).

Understanding Cron Syntax

Every cron job is defined by a single line in the crontab file. The line has five time fields followed by the command to run. Understanding what each field means is the foundation of using cron effectively.

*Minute
*Hour
*Day/Month
*Month
*Day/Week
/path/to/command.shCommand
Minute0 – 59
Hour0 – 23
Day of Month1 – 31
Month1 – 12
Day of Week0 – 7 (0&7=Sun)

Special Characters

Five special characters let you build any schedule imaginable:

CharacterMeaningExample
*Every possible value* * * * * — every minute
,List of values0 9,18 * * * — at 9 AM and 6 PM
-Range of values0 9-17 * * * — every hour 9 AM–5 PM
/Step / interval*/15 * * * * — every 15 minutes
LLast (day of month/week)0 0 L * * — last day of month (some cron variants)

Essential Crontab Commands

All cron management happens through the crontab command. You never edit the crontab file directly — always use these commands:

🖥️ Bash — Crontab Commands
# Open your crontab for editing (creates one if it doesn't exist)
crontab -e

# List all your current cron jobs
crontab -l

# Remove/delete your entire crontab (CAREFUL — no confirmation!)
crontab -r

# Edit another user's crontab (root only)
crontab -u username -e

# View another user's crontab (root only)
crontab -u username -l

# Check if the cron service is running
systemctl status cron        # Debian / Ubuntu
systemctl status crond       # CentOS / RHEL / AlmaLinux

# Start / restart cron service
sudo systemctl restart cron
⚠️

Never run crontab -r when you meant crontab -e. The -r flag silently deletes your entire crontab with no confirmation prompt. Always back up your crontab first: crontab -l > crontab_backup.txt

Your First Cron Job — Step by Step

1

Open your crontab

Run crontab -e in your terminal. The first time, it will ask you to choose an editor — select nano if you are a beginner (option 1 on most systems).

2

Write your cron expression

Add a new line at the bottom of the file. For example, to run a Python script every day at 2 AM: 0 2 * * * /usr/bin/python3 /home/user/myscript.py

3

Use absolute paths

Cron runs in a minimal environment. Always use full absolute paths for both the command and any files it references. Find Python's path with which python3.

4

Save and exit

In nano: press Ctrl+O then Enter to save, then Ctrl+X to exit. Cron will display "crontab: installing new crontab" confirming your changes are active.

5

Make your script executable

If running a shell script, make it executable first: chmod +x /home/user/myscript.sh. Python scripts called via /usr/bin/python3 do not need this.

⏰ Build your cron expression visually

Use our free Cron Generator — choose your schedule with dropdowns, see the cron expression and next-run times instantly. No memorizing syntax required.

⏰ Open Cron Generator →

20+ Real-World Cron Job Examples

Copy and adapt any of these examples directly into your crontab:

⏰ Crontab — Common Examples
# ── Every minute ──────────────────────────────
* * * * * /usr/bin/python3 /home/user/monitor.py

# ── Every 5 minutes ───────────────────────────
*/5 * * * * /home/user/check_api.sh

# ── Every 15 minutes ──────────────────────────
*/15 * * * * /usr/bin/php /var/www/html/cron.php

# ── Every hour (at :00) ───────────────────────
0 * * * * /home/user/hourly_task.py

# ── Every day at midnight ─────────────────────
0 0 * * * /home/user/daily_backup.sh

# ── Every day at 2:30 AM ──────────────────────
30 2 * * * /usr/bin/python3 /home/user/scraper.py

# ── Every weekday (Mon–Fri) at 9 AM ───────────
0 9 * * 1-5 /home/user/send_report.py

# ── Every Monday at 8 AM ─────────────────────
0 8 * * 1 /home/user/weekly_digest.sh

# ── First day of every month ─────────────────
0 0 1 * * /home/user/monthly_invoice.py

# ── Every January 1st at noon ────────────────
0 12 1 1 * /home/user/yearly_cleanup.sh

# ── Every day at 9 AM and 6 PM ───────────────
0 9,18 * * * /home/user/check_prices.py

# ── Every 2 hours ────────────────────────────
0 */2 * * * /home/user/sync_data.sh

# ── Weekdays between 9 AM–5 PM, every hour ───
0 9-17 * * 1-5 /home/user/office_hours_task.py

# ── Every Sunday at 3 AM (DB backup) ─────────
0 3 * * 0 mysqldump -u root mydb > /backups/mydb.sql

# ── Clear temp files every night ─────────────
0 1 * * * find /tmp -type f -mtime +7 -delete

# ── Restart Nginx every Sunday at 4 AM ───────
0 4 * * 0 systemctl restart nginx

# ── Pull latest code from GitHub daily ───────
0 3 * * * cd /var/www/myapp && git pull origin main

# ── Run Laravel scheduler (every minute) ─────
* * * * * cd /var/www/laravel && php artisan schedule:run >> /dev/null 2>&1

# ── Python virtualenv script ─────────────────
0 6 * * * /home/user/myapp/venv/bin/python /home/user/myapp/run.py

Special Cron Strings (Shortcuts)

Most modern cron implementations support special @strings as convenient aliases for common schedules. These are much easier to read than five-field expressions:

StringEquivalentRuns
@rebootOnce at system startup
@yearly0 0 1 1 *Once a year, Jan 1st midnight
@annually0 0 1 1 *Same as @yearly
@monthly0 0 1 * *First day of each month, midnight
@weekly0 0 * * 0Every Sunday at midnight
@daily0 0 * * *Every day at midnight
@midnight0 0 * * *Same as @daily
@hourly0 * * * *Every hour at :00
⏰ Crontab — Special Strings
# Run a script on every server reboot
@reboot /home/user/start_services.sh

# Daily database backup
@daily /home/user/backup_db.sh

# Weekly log cleanup
@weekly find /var/log/myapp -name "*.log" -mtime +30 -delete

# Monthly report generation
@monthly /usr/bin/python3 /home/user/monthly_report.py

Environment Variables in Cron

One of the most common reasons cron jobs fail silently is missing environment variables. Cron runs in a stripped-down shell environment — it does not load your ~/.bashrc or ~/.profile, so variables like PATH, HOME and any custom variables you rely on are often not available.

⏰ Crontab — Setting Environment Variables
# Set environment variables at the TOP of your crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/youruser
MAILTO=""   # Suppress email output

# Custom variables (API keys, app paths)
APP_DIR=/var/www/myapp
API_KEY=your_api_key_here

# Now your jobs can use these variables
0 6 * * * cd $APP_DIR && /usr/bin/python3 run.py

Best practice: Set MAILTO="" at the top of your crontab to silence the default behaviour of emailing output to the local root mailbox. Instead, redirect output to a log file explicitly in each job line.

Logging and Debugging Cron Jobs

When a cron job does not run as expected, logging is your only debugging tool. Always redirect both standard output and standard error to a log file so you can see exactly what happened.

⏰ Crontab — Logging Patterns
# Redirect stdout AND stderr to a log file (append mode)
0 2 * * * /usr/bin/python3 /home/user/script.py >> /home/user/logs/script.log 2>&1

# Separate stdout and stderr logs
0 2 * * * /home/user/script.sh >> /logs/out.log 2>> /logs/err.log

# Discard all output (silent mode)
0 2 * * * /home/user/script.sh > /dev/null 2>&1

# Timestamped log entry
0 2 * * * echo "[$(date)] Starting job" >> /logs/job.log && /home/user/script.py >> /logs/job.log 2>&1

Checking System Cron Logs

🖥️ Bash — View Cron System Logs
# View all cron-related entries in syslog (Debian/Ubuntu)
grep CRON /var/log/syslog

# Watch cron log in real time
tail -f /var/log/syslog | grep CRON

# On systems using journald (CentOS/RHEL)
journalctl -u crond -f

# Watch your script's log file in real time
tail -f /home/user/logs/script.log

Troubleshooting — Why Is My Cron Job Not Running?

Here are the most common causes of cron jobs failing and how to fix each one:

ProblemCauseFix
Job never runsScript not executablechmod +x /path/to/script.sh
Command not foundRelative path usedUse full path — run which python3 to find it
Script runs manually but not in cronMissing environment varsSet PATH at top of crontab or source your profile in the script
Cron service not runningDaemon stoppedsudo systemctl start cron
Wrong timezoneServer in UTC, you expect local timeAdd CRON_TZ=America/New_York at top of crontab
Syntax error in crontabMalformed expressionValidate at WebTigers Cron Generator
Script output filling diskNo output redirectionAdd >> /log/file.log 2>&1 or > /dev/null 2>&1

Cron with Python Scripts

Python is one of the most popular languages for cron automation. Here are the key patterns for running Python scripts reliably via cron — especially when using virtual environments.

⏰ Crontab — Python Best Practices
# ── System Python ──────────────────────────────────────
0 6 * * * /usr/bin/python3 /home/user/script.py >> /home/user/cron.log 2>&1

# ── Virtual Environment (recommended) ──────────────────
# Use the venv's python directly — no need to activate
0 6 * * * /home/user/myproject/venv/bin/python /home/user/myproject/script.py >> /home/user/cron.log 2>&1

# ── Change directory first (for relative imports) ──────
0 6 * * * cd /home/user/myproject && /home/user/myproject/venv/bin/python script.py >> cron.log 2>&1

# ── Multiple commands in sequence ──────────────────────
0 6 * * * cd /home/user/myproject && git pull && venv/bin/python run.py >> logs/run.log 2>&1

# ── Email scraper example (from our other tutorial) ────
0 2 * * * /home/user/email-scraper/venv/bin/python /home/user/email-scraper/pipeline.py >> /home/user/email-scraper/logs/scraper.log 2>&1

Cron with PHP and Laravel

PHP applications often use cron for scheduled jobs. Laravel has its own scheduler that requires a single cron entry — all other schedules are defined in PHP code.

⏰ Crontab — PHP and Laravel
# ── Plain PHP script ───────────────────────────────────
0 0 * * * /usr/bin/php /var/www/html/cron/daily_cleanup.php >> /var/log/php-cron.log 2>&1

# ── Laravel Scheduler (single entry, handles all tasks) ─
* * * * * cd /var/www/laravel && php artisan schedule:run >> /dev/null 2>&1

# ── WordPress WP-Cron via CLI (bypass HTTP trigger) ────
*/5 * * * * /usr/bin/php /var/www/wordpress/wp-cron.php > /dev/null 2>&1