/
Operating System

systemd Timers vs Cron

systemd timers are the built-in scheduling mechanism on nearly every modern Linux distribution that uses systemd as its init system, offering dependency management, structured logging via journald, and a more expressive calendar syntax than cron's 5 fields — at the cost of needing two unit files instead of one crontab line.

Syntax Notes

Timers use OnCalendar= expressions, a different (and more expressive) syntax than cron: DayOfWeek Year-Month-Day Hour:Minute:Second, with wildcards (*), ranges, and steps (/) similar in spirit to cron but not directly interchangeable — for example '*-*-* 02:00:00' for daily at 2 AM, or 'Mon..Fri 09:00' for weekdays at 9 AM.

Examples

mybackup.service
[Unit]
Description=Run backup script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
mybackup.timer (daily at 2 AM)
[Unit]
Description=Run backup daily

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
Enable and start the timer
sudo systemctl enable --now mybackup.timer

Gotchas

  • A timer file alone does nothing — it must reference a matching .service file with Type=oneshot, and both files need matching base names (mybackup.timer + mybackup.service) or an explicit Unit= directive pointing to the service.
  • OnCalendar syntax looks similar to cron at a glance but isn't compatible with it — porting a crontab entry means translating the expression, not copying it verbatim. Use `systemd-analyze calendar 'EXPRESSION'` to preview and validate before deploying.
  • Without Persistent=true in the [Timer] section, a missed run (machine was off at the scheduled time) is simply skipped rather than caught up on next boot — the closest systemd equivalent to anacron's catch-up behavior.

Best Practices

  • Validate any OnCalendar expression with `systemd-analyze calendar 'your-expression' --iterations=5` before enabling the timer — it prints the next several run times so a typo shows up before it causes a missed job.
  • Use Persistent=true for anything that should catch up after downtime (backups, cleanup jobs) — it's the direct equivalent of cron+anacron's missed-job behavior, and it's off by default.
  • Check timer status and history with `systemctl list-timers` and `journalctl -u mybackup.service` — systemd's built-in logging is a genuine advantage over plain cron, which requires the job itself to handle its own logging.

Frequently Asked Questions

Should I switch from cron to systemd timers?
If cron is already meeting your needs, there's little reason to switch. Timers are worth it specifically when you need dependency ordering (run after another service starts), built-in catch-up for missed runs, or centralized logging via journald without setting any of that up yourself.
Can I just paste my crontab entry's schedule into OnCalendar?
No — the syntaxes aren't compatible. A 5-field cron expression needs to be translated into systemd's OnCalendar format, which uses a different field order and wildcard style, not copied as-is.
How do I see when a systemd timer will next run?
Run `systemctl list-timers` to see every active timer's next scheduled run, or `systemd-analyze calendar 'OnCalendar-expression'` to preview run times for an expression before deploying it.