If you've ever needed a script to run at 2 AM every night, a backup to execute every Sunday, or a health check to ping every 5 minutes, you need cron. Cron is the time-based job scheduler built into virtually every Unix-like operating system. It's been automating tasks since 1975, and it's still the go-to solution for scheduling on Linux servers today.
The only problem? Cron syntax is notoriously confusing. 0 4 * * 2-4 means what, exactly? That's where a cron job generator saves the day — you describe what you want in plain terms, and it gives you the correct expression.
This guide covers everything: how cron works, how to read and write expressions, and how to use a generator to build schedules without memorizing syntax.
Cron is a daemon (background process) that runs on Linux, macOS, and other Unix-based systems. It reads a configuration file called a crontab (cron table) and executes commands at specified times. Each line in a crontab represents one scheduled job.
A cron job consists of two parts:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of week (0 - 6, Sun = 0)
# │ │ │ │ │
# * * * * * command to execute
0 2 * * * /home/user/backup.sh
Each cron expression has five fields separated by spaces:
| Field | Values | Special Characters |
|---|---|---|
| Minute | 0–59 | * , - / |
| Hour | 0–23 | * , - / |
| Day of Month | 1–31 | * , - / |
| Month | 1–12 | * , - / |
| Day of Week | 0–6 (0 = Sunday) | * , - / |
* (asterisk) — Matches any value. * * * * * means "every minute of every hour of every day.", (comma) — Lists multiple values. 0,15,30,45 * * * * runs at minutes 0, 15, 30, and 45.- (hyphen) — Defines a range. 0 9-17 * * * runs every hour from 9 AM to 5 PM./ (slash) — Defines step values. */10 * * * * runs every 10 minutes. 0 */2 * * * runs every 2 hours.Here are the schedules you'll use most often:
| Schedule | Expression | Description |
|---|---|---|
| Every minute | * * * * * | Runs 1,440 times per day |
| Every 5 minutes | */5 * * * * | 288 times per day |
| Every hour | 0 * * * * | At minute 0 of every hour |
| Every day at midnight | 0 0 * * * | 00:00 daily |
| Every day at 2:30 AM | 30 2 * * * | 02:30 daily |
| Every Monday at 9 AM | 0 9 * * 1 | Weekly on Monday |
| First of every month | 0 0 1 * * | Monthly at midnight |
| Weekdays at 5 PM | 0 17 * * 1-5 | Mon–Fri at 5 PM |
| Every 6 hours | 0 */6 * * * | 0:00, 6:00, 12:00, 18:00 |
| Every Sunday at noon | 0 12 * * 0 | Weekly on Sunday |
0 0 * * 0 for Sunday midnight (day 0 = Sunday in most cron implementations) or 0 0 * * 7 which also means Sunday on some systems. When in doubt, use the generator to avoid ambiguity.
A cron job generator eliminates the need to memorize syntax. Here's how to use one effectively:
Instead of writing raw expressions, describe what you need: "Run every day at 3 AM" or "Run every Monday, Wednesday, and Friday at 9:30 AM." The generator translates this into the correct cron syntax.
Most generators offer dropdowns or input fields for each cron field. You can also use preset options for common schedules. Our generator supports both approaches — pick whichever feels more natural.
A good generator shows what the expression means in plain English. Always double-check this. 0 4 * * 2-4 means "At 4:00 AM, Tuesday through Thursday" — not "every 2 to 4 hours." The description prevents costly misunderstandings.
Once you have the correct expression, add it to your crontab:
# Edit your crontab
crontab -e
# Add your job (expression + command)
0 3 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
# List existing cron jobs
crontab -l
Don't just set it and forget it. Verify that your job runs correctly:
# Check system cron logs (Ubuntu/Debian)
grep CRON /var/log/syslog
# Check cron logs (CentOS/RHEL)
grep CRON /var/log/cron
# Add logging to your cron job
0 3 * * * echo "$(date): Starting backup" >> /var/log/backup.log && /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
Cron runs with a minimal environment — your $PATH is not the same as your interactive shell. Always use absolute paths for scripts and commands:
# ❌ Bad - relative path, may fail
* * * * * python3 backup.py
# ✅ Good - absolute paths
* * * * * /usr/bin/python3 /home/user/scripts/backup.py
Cron sends output via email by default, which you probably don't check. Redirect stdout and stderr to a log file:
0 2 * * * /home/user/backup.sh >> /var/log/backup.log 2>&1
If your script needs specific environment variables, define them in the crontab:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
NODE_ENV=production
0 * * * * /home/user/node-scripts/sync.js
Cron uses the system's local time zone. If your server is in UTC but you need a job to run at 3 PM Eastern, you need to account for the offset (UTC-5 standard, UTC-4 daylight saving). Alternatively, set the TZ variable:
TZ=America/New_York
0 15 * * * /home/user/daily-report.sh
systemd timers or external schedulers that handle DST more gracefully.
The classic crontab supports five fields. Users have their own crontabs (crontab -e), and there's a system-wide crontab at /etc/crontab that includes an additional user field.
Modern Linux distributions are moving toward systemd timers, which offer more features (dependency management, logging, monotonic timers). But cron remains widely used and supported.
Platforms like AWS EventBridge, GitHub Actions, Vercel Cron Jobs, and Kubernetes CronJobs use cron expression syntax (sometimes with six fields, adding seconds). Our generator supports both five-field and six-field expressions.
If you're scheduling tasks in Node.js, libraries like node-cron and agenda use cron syntax directly:
const cron = require('node-cron');
// Run every day at 2 AM
cron.schedule('0 2 * * *', () => {
console.log('Running daily backup...');
});
Cron doesn't natively support "last day of month," but you can approximate it:
# Run on days 28-31 (covers all month lengths)
0 0 28-31 * * [ "$(date +%d -d tomorrow)" == "01" ] && /home/user/monthly-report.sh
# Run every other Sunday
0 0 * * 0 test $(( $(date +\%s) / 86400 \% 14 )) -eq 0 && /home/user/biweekly.sh
# Monday through Friday at 9 AM
0 9 * * 1-5 /home/user/workday-task.sh
* and */1?They produce the same result for most fields. * means "every possible value" and */1 means "every 1st value starting from 0." In practice, they're interchangeable. Use * for readability.
Yes. You can manually run the command to verify it works, or use a tool that shows upcoming execution times for a given expression. Our generator displays the next 10 scheduled run times so you can verify the schedule is correct.
Check these common issues: absolute paths (not relative), correct permissions on the script (chmod +x), cron daemon is running (systemctl status cron), and check the logs for error messages.
Comment it out by adding # at the beginning of the line in your crontab:
# 0 2 * * * /home/user/backup.sh # temporarily disabled
Stop guessing cron syntax. Our Cron Job Generator lets you build schedules visually, see human-readable descriptions, and preview upcoming execution times. Supports five-field and six-field (with seconds) expressions. Works on desktop and mobile.
Try the Cron Job Generator →Cron is one of the most powerful tools in a sysadmin's arsenal, but its syntax has a steep learning curve. A cron job generator bridges that gap — letting you define schedules in terms you understand and get correct expressions every time. Combine that with the best practices in this guide, and you'll be scheduling tasks like a seasoned professional in no time.
Bookmark this guide, save the generator, and never struggle with cron syntax again.