Linux Administration·6 min read·

systemd Timers vs Cron: Which Scheduler for Modern Servers?

Compare systemd timers with cron across persistence, logging, dependencies, and randomization, and learn when each scheduler is the right tool.

NB

Netbay Cloud Team

Netbay Engineering

On this page

Cron has scheduled tasks on Unix for forty years and is still a perfectly good tool. But every modern server also runs systemd, and systemd timers solve several chronic cron problems: jobs that silently stop running, missed executions during downtime, overlapping runs of long jobs, and logs you have to find in mail spools. This post compares the two honestly, because the right answer on most machines is both.

What a Timer Actually Is

A systemd timer is not one file but a pair: a oneshot service that does the work, and a timer unit that says when to trigger it. Here is the service half, at /etc/systemd/system/backup.service.

ini
[Unit]
Description=Nightly database backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

And the timer half, at /etc/systemd/system/backup.timer.

ini
[Unit]
Description=Run nightly backup at 02:30

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

[Install]
WantedBy=timers.target

Enable the timer, not the service: systemctl enable --now backup.timer. The service unit now exists purely as the thing the timer pokes, and it gets its own logs, its own restart behavior, and its own resource limits like any other service.

Timers also come in a monotonic flavor. Instead of OnCalendar=, directives like OnBootSec=15min, OnStartupSec=, and OnUnitActiveSec=1h fire relative to events rather than wall-clock times. They compose — one timer can carry several On*= directives and fires on whichever comes due first — and they never misbehave when the clock jumps, which makes them the right choice for cleanup jobs and cache eviction that only care about elapsed time.

cron vs systemd timers cron one crontab per user 30 2 * * * syntax no missed-run recovery mails root on failure no dependencies or sandboxing minimal and universal vs systemd timers service + timer unit pair OnCalendar=, Persistent= runs missed jobs at next boot journalctl -u backup.service After=, Wants=, sandboxing systemctl list-timers

Where Timers Beat Cron

  • Persistence: Persistent=true means that if the machine was down at 02:30, the job runs at the next boot. A cron job missed while the server was off is simply gone.
  • Logging: each job writes to the journal under its own unit, so journalctl -u backup.service shows every run, its output, and its exit status. Cron traditionally emails root and hopes someone reads it.
  • Dependencies: the service can declare After=network-online.target or Wants=postgresql.service like any other unit. Scheduling and ordering stop being separate problems.
  • Jitter: RandomizedDelaySec=15m staggers jobs across a fleet so a thousand servers do not hit the same backup target at the same second.
  • Sandboxing: the whole hardening toolkit, from User= to PrivateTmp=, applies to scheduled jobs exactly as it does to daemons.

Where Cron Still Wins

Cron remains better when the job is a one-line command in a user crontab, when you are on a minimal system where typing crontab -e is faster than writing two unit files, or when third-party tooling assumes a crontab exists. The calendar syntax is also genuinely harder: OnCalendar=*-*-* 02:30:00 is more expressive than 30 2 * * *, but nobody intuits it on first contact. Which is exactly why the next section exists.

Verify Before You Deploy

bash
systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
systemd-analyze calendar weekly
systemctl list-timers --all

systemd-analyze calendar prints the next several times an expression will fire, which catches off-by-one mistakes before they catch you. Once a timer is enabled, list-timers shows every timer on the machine with its last and next trigger, and systemctl list-timers --all is a better morning checklist than reading a dozen crontabs.

The Practical Decision

If a job must not be silently missed, or you want logs and dependencies, use a timer. If it is a trivial one-liner and losing a run during a maintenance window is acceptable, cron is fine. The two coexist on the same machine without conflict — the only real mistake is assuming cron is the default answer on a systemd system.

Scale the tooling to the job: a timer pair for a ten-second cleanup is heavier than one crontab line, but it buys supervision for free, and that trade is worth making per job rather than per server.

Takeaway: timers give scheduled jobs the same supervision as services — journal entries, dependencies, persistence, and sandboxing — and systemd-analyze calendar removes the last real argument against learning the syntax.

Schedule your first timer on a fresh instance: deploy an Ubuntu 24.04 VPS on Netbay in under 60 seconds at netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance