Cron vs Systemd Timers: Which Should You Use?
Here's the short verdict on cron vs systemd timers: use cron for simple, personal, or portable jobs; use systemd timers when you need logging, missed-run catch-up, or dependencies on other services. Cron wins on simplicity — one line and you're done. Systemd timers win on operational robustness — at the cost of writing two unit files.
Both schedulers run scheduled tasks on Linux reliably. The right choice depends on what happens around the job: what you do when it fails, what happens if the machine was off, and how much machinery you're willing to maintain. Let's compare them properly.
Quick Comparison Table
| Feature | Cron | Systemd timers |
|---|---|---|
| Setup | One crontab line | Two files (.service + .timer) |
| Logging | Email or manual redirection | Automatic, via journald |
| Missed runs (machine off) | Skipped* | Caught up with Persistent=true |
| Dependencies | None | Full systemd ordering (After=, Requires=) |
| Randomized delay | Limited support | RandomizedDelaySec= built in |
| Sub-minute precision | No (1-minute floor) | Yes (OnUnitActiveSec=30s) |
| Resource control | No | CPU/memory limits via unit options |
| Portability | Everywhere Unix-like | Systemd distros only |
| Learning curve | Minutes | Hours |
*Anacron covers daily/weekly/monthly catch-up on many distros, but not arbitrary schedules.
The Same Job, Both Ways
Seeing both side by side makes the trade-off concrete. Say we want a backup at 2:30 a.m. daily.
Cron — one line via crontab -e:
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Systemd — two files. First /etc/systemd/system/backup.service:
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Then /etc/systemd/system/backup.timer:
[Unit]
Description=Run backup nightly at 2:30
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
Enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
More ceremony, clearly. What do you get for it?
Where Systemd Timers Pull Ahead
Logging comes free
Every run's output lands in the journal automatically:
journalctl -u backup.service --since yesterday
With cron, you either redirect output yourself on every line or dig through local mail. For debugging a 3 a.m. failure, journalctl is a genuine quality-of-life upgrade.
Missed runs get caught up
Persistent=true means: if the machine was off at 2:30, run the job at next boot. Cron simply skips missed runs — if your laptop sleeps through the schedule, the backup never happens.
Dependencies and ordering
A timer's service is a full systemd unit. Need the backup to wait for the network, or never run while another service is active? After=network-online.target handles what cron can't express at all.
Spreading the load
RandomizedDelaySec=600 staggers a fleet of servers so a thousand machines don't hammer the backup target at exactly 02:30:00. On its own, vanilla cron has no native equivalent.
Where Cron Still Wins
- Speed of setup. One line versus two files, a
daemon-reload, and anenable. For a quick log-cleanup job, cron's friction is unbeatable. - Portability. A crontab line works on any Unix-like system — old Linux, BSD, macOS, minimal containers. Systemd timers require systemd.
- Ubiquity of knowledge. Every sysadmin can read
30 2 * * *.OnCalendar=*-*-* 02:30:00still sends people to the manual. - Web hosting reality. Shared hosts and cPanel expose cron, not systemd. Often cron is your only option.
OnCalendar Syntax at a Glance
Systemd's time format differs from cron's five fields. The shape is DayOfWeek Year-Month-Day Hour:Minute:Second:
OnCalendar=daily # midnight every day
OnCalendar=*-*-* 02:30:00 # every day at 2:30 a.m.
OnCalendar=Mon *-*-* 09:00:00 # Mondays at 9 a.m.
OnCalendar=*:0/15 # every 15 minutes
Test any expression before deploying:
systemd-analyze calendar "Mon *-*-* 09:00:00"
The command prints the normalized form and the next elapse time, so you can confirm the schedule before the timer ever fires — systemd's answer to crontab.guru.
Migrating a Cron Job to a Timer
The translation is mechanical once you've done it twice:
- Move the command into a
.servicefile withType=oneshot. - Convert the five cron fields to an
OnCalendar=expression (verify withsystemd-analyze calendar). - Add
Persistent=trueif missed runs should catch up. daemon-reload, thenenable --nowthe timer.- Delete the crontab line only after
systemctl list-timersshows a sensible next-run time and one run has appeared injournalctl -u yourjob.service.
Keep both scheduled in parallel for a day only if the job is idempotent — otherwise you'll run it twice.
Common Mistakes
- Forgetting
Persistent=trueand then wondering why a laptop's timer never fires — the machine is asleep at the scheduled moment. - Enabling the service instead of the timer. Run
systemctl enable backup.timer, notbackup.service. Enabling the service can run the job at every boot. - Skipping
daemon-reloadafter editing unit files, so changes silently don't apply. - Rewriting every cron job as a timer on principle. A five-line crontab that has worked for years does not need migrating.
- Assuming cron logs somewhere useful. It logs that jobs started (syslog), not what they printed. That's why redirection matters.
So Which Should You Choose?
Choose cron when:
- The job is simple and self-contained
- You need portability across systems
- You're on shared hosting or a minimal container
- The occasional missed run is acceptable
Choose systemd timers when:
- You need to know exactly what happened on every run (journald)
- Missed runs must be made up (
Persistent=true) - The job depends on other services or the network
- You want randomized delays or resource limits
Many production systems sensibly use both: cron for small housekeeping, timers for anything business-critical.
Conclusion
The cron vs systemd timers question has a practical answer: cron for convenience and portability, systemd timers for observability and robustness. Neither is obsolete, and the skills transfer — a schedule is a schedule, whether it's written 30 2 * * * or OnCalendar=*-*-* 02:30:00.
If you're staying with cron, our cron syntax guide and crontab examples will make you fast. If you're going the timer route, pair it with proper monitoring so failures never go unnoticed either way.
Frequently Asked Questions
Are systemd timers better than cron?
They're more capable — built-in logging, missed-run catch-up, and service dependencies — but not universally better. Cron is simpler, more portable, and entirely sufficient for basic scheduled tasks on Linux.
Do systemd timers replace cron?
On systemd-based distros they can, and some minimal server setups ship without cron installed. But cron remains standard nearly everywhere, and the two coexist without conflict on the same machine.
How do I see all active systemd timers?
Run systemctl list-timers. It shows each timer's next scheduled trigger, the time remaining, the last run, and the service unit it activates.
Can a systemd timer run more often than once a minute?
Yes. Unlike cron's one-minute floor, timers support second-level scheduling — for example OnUnitActiveSec=30s re-runs a job 30 seconds after its last activation.
What happens to a cron job if the server is off at the scheduled time?
Standard cron skips it entirely; there's no catch-up. Systemd timers with Persistent=true run the missed job as soon as the machine is back up — a key difference for laptops and intermittently-running machines.
Need the expression itself? Build and test any cron schedule in our free visual generator — with live upcoming-run previews in Unix and Quartz formats.
Related guides
References
- freedesktop.org — systemd.timer(5) manual — authoritative timer options reference
- Arch Wiki — systemd/Timers — excellent practical examples and cron comparison
- man7.org — crontab(5) manual page — the cron side of the comparison