DevOps
What Is a Cron Job? Complete Guide to Scheduling Tasks in Linux
A cron job is a scheduled task that runs automatically at a set time on Linux and Unix systems. This guide covers cron syntax, common examples, how to create and debug cron jobs, and when to use alternatives like systemd timers or cloud schedulers.
Advertisement
What Is a Cron Job?
A cron job is a task that is scheduled to run automatically on a Linux or Unix-based server at a specified time or interval. The name comes from Chronos, the Greek word for time. Cron jobs are used to automate repetitive tasks: sending reports, clearing temporary files, running database backups, fetching data from external APIs, and sending scheduled emails.
Cron is available on virtually every Linux distribution, macOS, and most Unix-based operating systems by default. It runs as a background service (called the cron daemon) that wakes up every minute, checks whether any scheduled jobs are due to run, and executes them. On modern Linux systems using systemd, the cron daemon is often replaced or supplemented by systemd timers, but traditional cron is still widely used and supported.
A single server may have dozens or hundreds of cron jobs defined across multiple users. System administrators define system-wide cron jobs for maintenance tasks. Developers define application-level cron jobs for data pipelines, cache warming, cleanup routines, and scheduled notifications. Operations teams use cron to automate infrastructure tasks like log rotation, certificate renewal with Certbot, and health check pings.
How the Cron Daemon Works
The cron daemon (crond on most systems) starts automatically when the server boots and runs continuously in the background. Every minute, it reads all crontab files — one per user plus system-wide cron directories — and checks whether any scheduled job matches the current time. If a match is found, it executes the corresponding command in a new process.
Cron reads job definitions from several locations. Each user has a personal crontab file managed with the crontab command. System-wide jobs are defined in /etc/crontab and in files placed in /etc/cron.d/. The directories /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, and /etc/cron.monthly/ contain scripts that run at those fixed intervals — drop a script into /etc/cron.daily/ and it will run once per day without writing a cron expression.
Each cron job runs in a minimal shell environment. The PATH variable is usually limited to /usr/bin and /bin, which is much shorter than your interactive shell PATH. Environment variables you have set in your .bashrc or .profile are not available in cron jobs. The working directory is typically the home directory of the user the job runs as. These differences are the most common source of cron jobs that work in the terminal but fail silently when run by cron.
The Five-Field Cron Syntax
A cron job definition has six parts: five time fields followed by the command to run. The five time fields specify when the job should execute: minute, hour, day of month, month, and day of week. They are written left to right in that order, separated by spaces, followed by the command.
The minute field accepts values 0 through 59. The hour field accepts 0 through 23 (using 24-hour format). The day-of-month field accepts 1 through 31. The month field accepts 1 through 12 or the three-letter abbreviations jan through dec. The day-of-week field accepts 0 through 7 (both 0 and 7 represent Sunday) or the three-letter abbreviations sun through sat.
An asterisk (*) in any field means every valid value for that field — every minute, every hour, every day. A value in a field means only that specific value. So 0 * * * * /path/to/script.sh runs the script at minute zero of every hour (i.e., on the hour). And 30 9 * * 1 /path/to/script.sh runs the script at 9:30 AM every Monday.
- Field 1 — Minute: 0-59
- Field 2 — Hour: 0-23 (24-hour format; 0 is midnight)
- Field 3 — Day of month: 1-31
- Field 4 — Month: 1-12 or jan-dec
- Field 5 — Day of week: 0-7 (0 and 7 are Sunday) or sun-sat
- Field 6 — Command: the shell command or script path to execute
Cron Special Characters: *, /, -, and ,
The asterisk (*) is the wildcard and means every possible value for that field. A slash (/) is used for step values: */5 in the minute field means every 5 minutes (0, 5, 10, 15... 55). A hyphen (-) defines a range: 1-5 in the day-of-week field means Monday through Friday. A comma (,) separates a list of values: 0,15,30,45 in the minute field means at minutes 0, 15, 30, and 45.
These special characters can be combined. 0-30/5 * * * * runs every 5 minutes but only during the first 30 minutes of each hour. 0 9-17 * * 1-5 runs every hour from 9 AM to 5 PM on weekdays. Understanding these combinations is the key to writing complex schedules without resorting to multiple separate cron entries.
Some cron implementations support an additional special character: the L (last) and W (nearest weekday) modifiers. These are available in some enhanced cron implementations and in job scheduling frameworks like Quartz (Java) and the cron syntax used in GitHub Actions, AWS EventBridge, and Azure Logic Apps, but are not part of the original POSIX cron specification and are not available in standard Linux cron.
Cron Shortcuts and Predefined Schedules
Most modern cron implementations support shorthand aliases for common schedules. @reboot runs the command once when the server starts. @hourly is equivalent to 0 * * * *. @daily is equivalent to 0 0 * * *. @weekly is equivalent to 0 0 * * 0. @monthly is equivalent to 0 0 1 * *. @yearly (or @annually) is equivalent to 0 0 1 1 *.
These shortcuts are more readable than the equivalent five-field expressions and should be used when they match the schedule you need. @reboot in particular is useful for starting services or scripts that should run once on server startup and cannot be managed with systemd services.
When writing cron expressions for cloud schedulers like AWS EventBridge, GitHub Actions, or Google Cloud Scheduler, note that these platforms sometimes use a six-field format that adds a seconds field at the beginning or a year field at the end. Always check the documentation for the specific platform — a standard Linux cron expression may not work without modification.
Common Cron Job Examples
Run a database backup every day at 2 AM: 0 2 * * * /usr/local/bin/backup-db.sh >> /var/log/backup.log 2>&1. The >> appends stdout to a log file. The 2>&1 redirects stderr to stdout so errors also go to the log.
Clear a temporary directory every Sunday at midnight: 0 0 * * 0 find /var/tmp/app-cache -type f -mtime +7 -delete. This deletes files in the cache directory that are older than 7 days. Run on Sundays to avoid disrupting weekday activity.
Send a weekly report every Monday at 9 AM: 0 9 * * 1 /usr/local/bin/send-weekly-report.py. Ping a website every 5 minutes and alert if it goes down: */5 * * * * /usr/local/bin/check-uptime.sh. Run a job on the first day of every month at 6 AM: 0 6 1 * * /usr/local/bin/monthly-invoice.sh.
- * * * * * command — runs every minute
- 0 * * * * command — runs every hour on the hour
- 0 0 * * * command — runs every day at midnight
- 0 0 * * 0 command — runs every Sunday at midnight
- 0 0 1 * * command — runs on the first of every month at midnight
- */15 * * * * command — runs every 15 minutes
How to Create a Cron Job with Crontab
To create a cron job, run crontab -e in the terminal. This opens your personal crontab file in the default text editor (usually nano or vi). Add one cron job definition per line using the five-field time format followed by the command. Save and exit the editor to install the new cron jobs. The cron daemon picks up the changes automatically without needing a restart.
To list all current cron jobs for the current user, run crontab -l. To remove all cron jobs for the current user, run crontab -r (be careful — this removes everything with no confirmation). To edit the crontab for a specific user as root, run crontab -u username -e. To list another user cron jobs, run crontab -u username -l.
When writing the command in a cron job, always use absolute paths to both the executable and any files it references. Do not rely on aliases or shell functions defined in your .bashrc. If the script uses tools in /usr/local/bin, include that in the PATH at the top of the crontab file or use the full path in the command: /usr/local/bin/python3 /home/user/scripts/job.py instead of python3 scripts/job.py.
# Open your personal crontab for editing
crontab -e
# List all current cron jobs
crontab -l
# Remove all cron jobs (no undo)
crontab -r
# Edit another user cron jobs (requires sudo)
sudo crontab -u www-data -eEnvironment Variables in Cron Jobs
Cron runs jobs in a minimal environment with a very short PATH. The default PATH in cron is usually /usr/bin:/bin, which does not include /usr/local/bin, /usr/sbin, or user-specific paths like /home/user/.local/bin. This is the most common reason a command works in the terminal but fails in cron — the cron job cannot find the executable.
To fix this, either use full absolute paths for every command in your cron job, or set the PATH variable at the top of your crontab file. Add a line like PATH=/usr/local/bin:/usr/bin:/bin before any job definitions. This path applies to all jobs in the crontab file. You can also set other environment variables the same way: MAILTO=user@example.com, HOME=/home/user, SHELL=/bin/bash.
If your script uses pyenv, nvm, rbenv, or any other version manager, those tools are typically loaded by your shell profile (.bashrc, .profile, .nvm/nvm.sh) which cron does not source. You must either activate the version manager explicitly in the cron command, use the full path to the version-managed binary (e.g., /home/user/.nvm/versions/node/v20.0.0/bin/node), or wrap the job in a small shell script that sources the necessary profile files.
Cron Job Logging and Debugging
By default, cron sends any output from jobs to the user email on the local system. On most servers without a local mail server configured, this email is dropped. To capture output for debugging, redirect stdout and stderr to a log file in the cron command: 0 * * * * /path/to/script.sh >> /var/log/myjob.log 2>&1. The >> appends to the log rather than overwriting it. The 2>&1 sends stderr to the same file as stdout.
To check the cron daemon logs to see whether jobs are being triggered, look in /var/log/syslog (Debian/Ubuntu) or /var/log/cron (CentOS/RHEL). Run grep CRON /var/log/syslog or tail -f /var/log/cron to see recent cron activity. These logs show when each job was started but not what output it produced.
The most common debugging checklist for a cron job that does not run: verify the cron expression is correct using a cron expression tester; verify the script is executable (chmod +x /path/to/script.sh); verify the PATH includes all needed executables; verify the working directory assumptions are correct; verify environment variables are set; check whether the cron daemon is running (systemctl status cron or service crond status); and review the cron log for error messages about the job.
When to Use Cron Alternatives
Cron is the right tool for simple, time-based task scheduling on a single server. It becomes a poor fit in several situations: when you need a job to run only once (use the at command instead), when you need sub-minute scheduling (cron minimum interval is one minute), when jobs need to run across multiple servers with coordination and deduplication, or when you need retry logic and failure handling.
systemd timers are a modern alternative on systems using systemd. They offer more precise timing (including sub-minute intervals), better logging through journald, dependency management, and the ability to catch up on missed runs after the system was off. For new systems where cron and systemd timers are both available, systemd timers are often the better choice for system-level tasks.
For application-level job scheduling in web applications, purpose-built tools are usually better than cron. BullMQ, Sidekiq, Celery Beat, and similar task queue schedulers provide retries, priority queues, monitoring, and failure handling that cron lacks. Cloud-native options like AWS EventBridge, Google Cloud Scheduler, and GitHub Actions scheduled workflows are better for distributed systems and teams that want to manage schedules as code in version control.
FAQ
What does a cron job do?
A cron job runs a specified command or script automatically at a scheduled time. The schedule is defined with a five-field expression specifying the minute, hour, day of month, month, and day of week when the job should run. Common uses include database backups, report generation, log rotation, cache clearing, sending scheduled emails, fetching data from APIs, and running maintenance scripts.
What is the format of a cron expression?
A cron expression has five time fields followed by the command: minute (0-59), hour (0-23), day of month (1-31), month (1-12), day of week (0-7, where 0 and 7 both mean Sunday), and then the command. An asterisk (*) in any field means every value for that field. For example, 30 9 * * 1-5 /path/to/script.sh runs the script at 9:30 AM Monday through Friday.
What does 0 * * * * mean in cron?
0 * * * * runs a job at minute 0 of every hour — that is, once per hour on the hour. The 0 specifies minute zero, and the four asterisks mean every hour, every day of the month, every month, and every day of the week. To remember: the fields go from smallest to largest time unit: minute, hour, day, month, weekday.
What is the difference between cron and crontab?
Cron is the scheduler daemon — the background service that runs on the server and executes scheduled jobs. Crontab is the file format (cron table) that defines the schedule and commands for cron jobs, and also the name of the command-line tool used to edit those files. You edit the crontab (file) using the crontab (command) to tell cron (daemon) what to run and when.
Can cron jobs run on Windows?
Cron is a Linux/Unix tool and is not natively available on Windows. The Windows equivalent is Task Scheduler, which provides a GUI and PowerShell interface for scheduling tasks. On Windows 10 and 11, you can run cron on Windows Subsystem for Linux (WSL) if you have WSL installed and configured. If you need to run cron-like jobs on a Windows server in production, Task Scheduler or a cross-platform job scheduler like Apache Airflow is the typical approach.
Why is my cron job not running?
The most common reasons are: the cron expression is wrong (check it with a cron expression tester like the one on this site); the script is not executable (run chmod +x /path/to/script.sh); the command uses a path not in cron PATH (use absolute paths or set PATH in the crontab); environment variables are missing (cron does not load .bashrc or .profile); or the cron daemon is not running (check with systemctl status cron). Check /var/log/syslog or /var/log/cron for cron daemon messages about the job.
How do I list all cron jobs on a Linux server?
To list your own cron jobs, run crontab -l. To see cron jobs for another user, run sudo crontab -u username -l. System-wide cron jobs are in /etc/crontab and in files under /etc/cron.d/. Scripts in /etc/cron.daily/, /etc/cron.weekly/, and /etc/cron.monthly/ are also scheduled by cron via the run-parts mechanism. Check all these locations for a complete picture of what is scheduled on the server.
Can I schedule a cron job to run every 30 seconds?
No. Standard cron has a minimum resolution of one minute. You cannot schedule a cron job to run every 30 seconds. A common workaround is to create two entries that run 30 seconds apart by adding sleep 30 to the second entry: one runs immediately and a second runs as * * * * * sleep 30 && /path/to/script.sh. For true sub-minute scheduling, use systemd timers, which support second-level precision, or an application-level scheduler within your code.
How do I redirect cron job output to a log file?
Append both stdout and stderr to a log file by adding >> /path/to/logfile.log 2>&1 at the end of the cron command. For example: 0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1. The >> appends to the file rather than overwriting it on each run. The 2>&1 redirects stderr (file descriptor 2) to stdout (file descriptor 1), so both streams go to the log file. Without this, any errors are silently dropped (or emailed to the system user, which is rarely monitored).
How do I delete a specific cron job?
Run crontab -e to open your crontab in the editor, delete or comment out the line for the job you want to remove (add # at the start of the line to disable it without deleting it), then save and exit. The change takes effect immediately. To remove all your cron jobs at once, run crontab -r, but this deletes everything with no confirmation or undo, so be careful.
Related free tools
If you want to turn this topic into action, use one of ShortIQ's free tools for campaign planning, UTM structure, or QR distribution.
Continue Reading
Explore more guides on link shortener SaaS strategy, Bitly alternatives, and white label link management.
Free newsletter
Get new guides in your inbox
We publish practical guides on dev tooling, prompt engineering, marketing workflows, and deployment. No fluff — straight to the point.
No spam. Unsubscribe any time.
Was this article helpful?
Tell us if this guide solved the problem or what was still missing. We use this to improve the blog and only follow up if you explicitly allow it.