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.

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

See also

  • 0164 systemd services: systemctl and journalctl basics systemd starts and supervises services on most Linux servers. systemctl starts, stops and enables them; journalctl shows their logs. Beginner · Concept · Linux Article Services & systemd 15 Oct 2026
  • 0165 Write a systemd service unit for your own app Turn any long-running program into a proper service: create a unit file, run it as an unprivileged user, restart it on failure… Intermediate · How-to · Linux Article Services & systemd 15 Oct 2026
  • 0167 Fix: Job for nginx.service failed because the control process exited with error code systemctl prints this when a service's start command exits with an error. The real reason is in journalctl; for nginx it is… Intermediate · Fix · Linux Article Networking & firewalls · Services & systemd 15 Oct 2026
  • 0168 Server health check script: disk, memory and failed units A dependency-free bash script that checks disk and inode usage, available memory, load, failed systemd units and pending reboots, and exits non-zero… Intermediate · Reference · Linux Script Disks, LVM & filesystems · Services & systemd 15 Oct 2026
  • 0255 Build a monitoring stack with Prometheus, node_exporter and Grafana on one Linux server Install Prometheus and node_exporter as systemd services, scrape and query host metrics with PromQL, then add Grafana with a dashboard and an… Intermediate · Tutorial · Linux Article Prometheus & Grafana · Services & systemd 15 Oct 2026
  • 0265 Turn a one-liner into a robust bash script: strict mode, options, logging, traps, locking and a schedule Grow a find-and-gzip one-liner step by step into a dependable bash script with strict mode, getopts, usage text, logging, error traps, dry-run,… Intermediate · Tutorial · Linux, macOS Article Services & systemd · Shell scripting 15 Oct 2026

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-admin +3,130 chars

Report a problem

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