Skip to content
Commitpedia
Log in Join & edit

Replace a cron job with a systemd timer

A systemd timer runs a service on a schedule like cron, but logs every run to the journal, can catch up missed runs and is easy to test by hand.

Not checked by a trusted editor yet Last edited Outdated?

Edit history of Replace a cron job with a systemd timer: 1 recorded edit
Edit history · 1 edit
Type
Article
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Reading
2 min

Cron is fine for simple jobs, but its output disappears unless mail is set up, a job missed while the server was off simply does not run, and testing “what will happen at 02:30” is awkward. A systemd timer is two small unit files: a .service that says what to run and a .timer that says when.

This example replaces the crontab line 30 2 * * * /usr/local/bin/backup.sh.

1. The service: what to run

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

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

Type=oneshot means the job runs to completion and exits, which is what a scheduled script does. There is no [Install] section: the timer starts this service, not the boot process.

2. The timer: when to run

Give the timer the same base name. If you do not set Unit=, a timer starts the service with the same name.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run the nightly backup at 02:30

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

[Install]
WantedBy=timers.target
  • OnCalendar=: a calendar expression. *-*-* 02:30:00 is every day at 02:30.
  • Persistent=true: remember the last run on disk; if the server was off at 02:30, run the job once as soon as the timer starts again.
  • RandomizedDelaySec=: add a random delay of up to 10 minutes, so many servers do not all hit the backup target at the same second.

3. Check the schedule before enabling

systemd-analyze calendar parses an expression and shows when it will next fire:

systemd-analyze calendar '*-*-* 02:30:00'
systemd-analyze calendar --iterations=5 'Mon..Fri *-*-* 09:00'

Useful expressions:

  • daily is *-*-* 00:00:00; weekly is Monday at 00:00.
  • Mon..Fri *-*-* 09:00: weekdays at 09:00.
  • *:0/15: every 15 minutes (minute 0, 15, 30, 45).
  • *-*-01 04:00:00: the first day of each month at 04:00.

For “every N minutes after the last run” instead of wall-clock times, use monotonic timers such as OnBootSec=5min together with OnUnitActiveSec=1h.

4. Enable the timer and test the job

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer      # NEXT and LAST run times

sudo systemctl start backup.service      # run the job right now, as a test
journalctl -u backup.service -n 30       # its output and exit status

Note that you enable the timer, not the service. Starting the service by hand is the easiest way to test the exact environment the timer will use.

5. Remove the old cron entry

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo crontab -e      # delete the backup line

Cron to timer cheat sheet

  • @reboot becomes OnBootSec=1min.
  • 0 * * * * becomes OnCalendar=hourly.
  • */10 * * * * becomes OnCalendar=*:0/10.
  • 0 3 * * 0 becomes OnCalendar=Sun *-*-* 03:00:00.
  • Cron’s MAILTO output becomes journalctl -u name.service.

If the job fails, systemctl status backup.service shows failed and it appears in systemctl --failed, which makes it easy to pick up with monitoring.

Official documentation

Did this work for you?

No votes yet. Be the first.

If it did not work, the report form below tells the editors what went wrong.

See also

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Commitpedia +3,130 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?