Cron vs at vs systemd Timers: When to Use Each
Linux has three main tools for scheduled job execution. Understanding the strengths of each helps you pick the right one for your use case — and avoid common pitfalls.
TL;DR — Quick Decision Guide
- cronUse for recurring schedules — backups every night, reports every Monday, cleanup every hour.
- atUse for one-time future tasks — send a reminder in 3 hours, run a script at 2am tomorrow.
- systemdUse when you need full logging, dependency handling, or want missed jobs to catch up — modern servers with systemd.
cron— the classic recurring scheduler
cron has been the standard Unix job scheduler since the 1970s. It reads a crontab file and runs each command when its 5-field time expression matches the current time.
# Edit your crontab
crontab -e # Run backup every night at 2am 0 2 * * * /usr/local/bin/backup.sh # Run report every Monday morning 0 9 * * 1 /usr/local/bin/weekly-report.sh # Clear tmp files every hour 0 * * * * find /tmp -mtime +1 -delete
Strengths
- • Simple, universal — every Linux/macOS system has it
- • No setup required for basic recurring jobs
- • Per-user crontabs for multi-user systems
Limitations
- • Missed jobs are silently skipped (no catchup)
- • Minimal PATH — common source of failures
- • No dependency management
at— one-time future execution
The at command schedules a command to run once at a specified time. It accepts natural language time specifications and captures your current environment automatically.
# Schedule a job for tomorrow at 9am echo "/path/to/script.sh" | at 9am tomorrow # Schedule in 2 hours echo "/path/to/script.sh" | at now + 2 hours # Schedule at a specific date/time echo "/path/to/script.sh" | at 14:30 Dec 31 # View the queue atq # Remove a job (job number from atq) atrm 3
Strengths
- • Natural language time input
- • Captures current shell environment automatically
- • Perfect for one-off administrative tasks
Limitations
- • One-time only — no recurring schedules
- • Not installed by default on all distros
- • Limited logging and monitoring
systemd timers— modern service-integrated scheduling
systemd timers are unit files that trigger services on a schedule. They integrate with systemd's dependency graph, logging (journald), and service management — making them more powerful but more complex to set up.
# /etc/systemd/system/backup.service
[Unit] Description=Nightly Backup [Service] Type=oneshot ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit] Description=Run backup nightly [Timer] OnCalendar=*-*-* 02:00:00 Persistent=true # Run missed jobs on next startup [Install] WantedBy=timers.target
# Enable and check status
sudo systemctl enable --now backup.timer systemctl list-timers journalctl -u backup.service
Strengths
- • Full journald logging — always
- •
Persistent=truecatches up missed jobs - • systemd dependency graph
- •
systemctl statusshows last run time
Limitations
- • More setup — requires two unit files
- • systemd-only (no macOS, no old Linux)
- • Steeper learning curve
Full Feature Comparison
| Feature | cron | at | systemd timer |
|---|---|---|---|
| Use case | Recurring schedules | One-time future execution | Recurring or one-time, service-integrated |
| Schedule syntax | 5-field cron expression | Natural language time ("tomorrow 9am") | Calendar events or monotonic timers |
| Persistence across reboots | Yes | Yes (queue survives reboot) | Yes, when enabled |
| Missed job handling | Skipped silently | Runs when system is available | Can run missed jobs with Persistent=true |
| Logging | syslog/journald (varies) | Limited | journald (full log, always) |
| Dependency management | None | None | Full systemd dependency graph |
| Environment | Minimal PATH, no shell env | Captures current env at schedule time | Explicit unit config |
| Email on output | Yes (via MAILTO) | Yes (by default) | No (log to journal) |
| Multi-user support | Per-user crontabs | Per-user queue | System or user units |
| Availability | Default on most Linux/macOS | Needs `at` package | Most modern Linux distros |
Write cron expressions the easy way
Use our visual builder to create cron expressions by selecting schedule options — no syntax memorization needed.