To set up a crontab, open your terminal and run crontab -e to edit your schedule file, then add a line defining when your script should run using five time fields. Save the file, and the cron daemon automatically picks up the new schedule without needing a restart. This works for most Linux and macOS systems, though some minimal containers require starting the cron service manually first.
Understanding the Crontab Structure
A standard crontab entry consists of five space-separated fields followed by the command you want to execute. Each field controls a specific time component, and they work together to define the exact moment your task runs. The order is always minute, hour, day of month, month, and day of week.
Here is what each field controls:
| Position | Field Name | Allowed Values | Example Meaning |
|---|---|---|---|
| 1 | Minute | 0–59 | Specific minute or range |
| 2 | Hour | 0–23 | Specific hour or range |
| 3 | Day of Month | 1–31 | Specific day within month |
| 4 | Month | 1–12 | Specific month number |
| 5 | Day of Week | 0–7 | Sunday (0 or 7) to Saturday (6) |
If you leave a field empty or use an asterisk (*), it means "every possible value" for that position. For example, * in the hour field means every hour. When you combine constraints, cron checks if the current time matches all five fields simultaneously. If it does, the command runs. If any field does not match, the command is skipped.
Writing Your First Cron Expression
Let’s build a schedule for a backup job that needs to run every Monday at 2:00 AM. This is a common requirement for weekly maintenance tasks that should happen before business hours.
Start with the minute field. We want exactly 2:00 AM, so the minute is 0. Next is the hour field. Since it is 2 AM, the hour is 2. Now look at the day fields. We want this every Monday, regardless of the date within the month. So, the day of month is * (any day), and the month is * (any month). Finally, the day of week. Monday is represented by 1 in standard cron syntax (Sunday is 0).
Putting it together, the expression looks like this:
0 2 * * 1 /usr/bin/rsync -av /src /dest
If you are unsure whether 1 means Monday or Sunday, remember that Sunday is traditionally 0. Some systems accept 7 for Sunday as well, but 1 for Monday is consistent across most implementations. If you need to verify this logic quickly, you can paste 0 2 * * 1 into CronExplain to see the plain-English explanation and the next ten firing times in your local timezone. This confirms that the schedule aligns with your specific server timezone settings before you commit it.
Verifying Schedule Logic and Next Fires
Before deploying a cron job, you need to confirm it fires when you expect. A common mistake is assuming the server timezone matches your local workstation timezone. If your server runs in UTC and you are in New York, a schedule meant for 2:00 AM local time might actually fire at 6:00 AM UTC if not configured correctly.
Take our example expression: 0 2 * * 1. This tells cron to fire at minute 0, hour 2, any day of month, any month, but only on day of week 1 (Monday). If your server timezone is UTC, this fires at 02:00 UTC. If you need it to fire at 02:00 EST, you might need to adjust the hour field to 7 (assuming EST is UTC-5) or configure the cron daemon’s timezone settings.
You can verify the logic by checking the next few occurrences. For 0 2 * * 1, the next fires would be consecutive Mondays at the specified hour. If you see unexpected days, check if the day-of-week field is conflicting with the day-of-month field. In standard cron, if both are restricted (not *), the job runs when either condition is met, which can cause duplicate executions. To avoid this, keep one of them as * unless you have a very specific reason to combine them.
Testing and Deploying Your Cron Job
Once your expression is written, you need to add it to the actual crontab file. Open your terminal and run:
crontab -e
This opens the current user’s crontab file in your default text editor. If you want to edit the system-wide crontab, you might need to use /etc/crontab or /etc/cron.d/, depending on your Linux distribution. For most user-level tasks, crontab -e is sufficient.
Add your line to the file. Ensure there are no trailing spaces after the command, as some parsers are strict. Save and exit the editor. The changes take effect immediately. You do not need to restart the cron service.
To verify it was added, list your current crontab entries:
crontab -l
You should see your expression listed. If you want to see logs to confirm execution, check your system logs or add output redirection to your command. For example, append >> /var/log/mybackup.log 2>&1 to your cron line to capture both standard output and errors. This helps you debug why a job might not be running or why it failed silently.
Common Pitfalls and Best Practices
Several issues frequently break cron jobs. The most common is relative paths. Cron runs with a minimal environment, often missing your usual PATH variables. Always use absolute paths for your scripts and binaries. Instead of calling rsync, call /usr/bin/rsync. Instead of ./script.sh, call /home/user/scripts/script.sh.
Another pitfall is timezone confusion. As mentioned earlier, cron respects the system timezone. If your server is in a different timezone than you expect, your job will fire at the wrong time relative to your local clock. You can check the system timezone with timedatectl or date. If you need to pin a specific timezone for shared team schedules, some cron implementations allow setting the TZ variable within the crontab file itself, though support varies by distribution.
Avoid using * for both day-of-month and day-of-week if you intend to restrict them. For example, 0 9 1 * * runs on the first day of every month. If you accidentally write 0 9 1 * 1, it runs on the first day of the month or any Monday. This is rarely what you want. Stick to restricting one field and leaving the other as *.
Finally, keep your schedules simple. Complex logic, like "every third Tuesday," is hard to express in standard cron syntax. It is often easier to write a simple script that checks the date internally and runs hourly, rather than trying to force a complex expression into the cron fields. Use tools like CronExplain to build simple expressions quickly, but rely on script logic for nuanced timing requirements. This keeps your crontab readable and easier to maintain over time.