Cron and systemd timers

general / published / guide #31 / ≈ 3 min read

Scheduling a task to run automatically — every night at 3 AM, every Monday, every 15 minutes — is one of the oldest tricks on Unix. There are two ways to do it today: the classic cron, and the newer systemd timers. Both are alive and well. This guide shows the same job written both ways so you can pick.

Cron, the old reliable

Every user has their own list of scheduled jobs, called a crontab (cron table). Edit yours with:

crontab -e

(Use sudo crontab -e for root's crontab.) The first time it asks which editor — nano is the friendliest pick.

Each line is one job:

30 3 * * * /usr/local/bin/backup.sh

That runs backup.sh at 3:30 AM every day. The five fields, left to right:

┌──── minute      (0-59)
│ ┌── hour        (0-23)
│ │ ┌── day of month  (1-31)
│ │ │ ┌── month       (1-12)
│ │ │ │ ┌── day of week (0-7, 0 and 7 both mean Sunday)
│ │ │ │ │
30 3 * * * /usr/local/bin/backup.sh

* means "every." So 30 3 * * * = minute 30 of hour 3, every day, every month, every weekday.

Common patterns

0 * * * *           # every hour, on the hour
*/15 * * * *        # every 15 minutes
0 9 * * 1-5         # 9 AM, Monday-Friday
0 0 1 * *           # midnight on the 1st of each month
@daily              # shortcut for 0 0 * * *
@hourly             # shortcut for 0 * * * *
@reboot             # at every boot

If you're not sure your expression is right, crontab.guru translates it into English.

List, edit, delete

crontab -l          # list your jobs
crontab -e          # edit
crontab -r          # delete ALL your jobs (no confirmation — careful)

Cron gotchas

  • No PATH. Cron runs with a minimal environment. backup alone won't be found; use the full path /usr/local/bin/backup.
  • Output goes to email. Anything your script prints is mailed to the user. On a server with no mail set up, this can fill /var/spool/mail. Redirect explicitly:
    30 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
  • The % sign is special — it's interpreted as a newline. Escape with \% if your command needs a literal percent.
  • The script needs to be executable — chmod +x backup.sh.

systemd timers, the modern alternative

A systemd timer is a small unit file that runs another unit file (the service) on a schedule. More verbose than cron, but with two big wins:

  • Logs go through journalctl, like every other service.
  • It catches up after downtime — if your laptop was asleep at 3 AM, the job runs when you wake up.

Same backup job, written as a timer

Two files in /etc/systemd/system/:

backup.service — what to run:

[Unit]
Description=Nightly backup

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

backup.timer — when to run it:

[Unit]
Description=Run backup nightly

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

[Install]
WantedBy=timers.target

Then enable the timer (not the service):

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

OnCalendar — the schedule mini-language

OnCalendar=hourly
OnCalendar=daily
OnCalendar=weekly
OnCalendar=*-*-* 03:30:00         # 3:30 AM every day
OnCalendar=Mon..Fri 09:00         # 9 AM weekdays
OnCalendar=*-*-01 00:00:00        # midnight on the 1st of each month

Persistent=true is the "catch up" knob — if the machine was off when the timer should have fired, run it as soon as the machine is back.

Useful inspection commands

systemctl list-timers                  # every timer, when it fires next
systemctl status backup.timer          # is this one ticking?
journalctl -u backup.service           # what did the last runs say?

Which should you use?

Cron systemd timer
Setup One line Two files
Logs Email or redirect journalctl out of the box
Catch up after downtime No Yes (Persistent=true)
Available on every distro? Yes Only systemd ones (most)
Available on FreeBSD? Yes No

For a quick personal job: cron is fewer keystrokes. For a serious service-like task on a Linux server: timers are nicer to live with.

← back to index