systemd Timers — Scheduled Jobs, the systemd Way
cron runs commands on a schedule. On a systemd system there's a second way: a timer that starts a service. Debian uses timers for its own jobs:
systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sat 2026-10-31 00:00:00 CET 2h 54min Fri 2026-10-30 00:00:00 CET 21h ago logrotate.timer logrotate.service
Sun 2026-11-01 03:10:22 CET 1 day 6h Sun 2026-10-25 03:10:22 CET 5 days ago e2scrub_all.timer e2scrub_all.service
NEXT and LEFT: when it runs next. LAST and PASSED: when it last ran. ACTIVATES: the service it starts.
A job in two files
Your backup script is ready: ~/scripts/docs-backup.sh packs ~/documents into ~/backups.
1. The service — what to run, /etc/systemd/system/docs-backup.service:
[Unit]
Description=Back up ~/documents
[Service]
Type=oneshot
User=student
ExecStart=/home/student/scripts/docs-backup.sh
Type=oneshot: a job that runs to its end, not a server that keeps running. User= — not as root.
sudo nano /etc/systemd/system/docs-backup.service
sudo systemctl daemon-reload
daemon-reload makes systemd read the new and changed unit files.
Try it by hand first — and read what it printed:
sudo systemctl start docs-backup.service
systemctl status docs-backup.service
journalctl -u docs-backup.service
Everything the script prints lands in the journal, with the time — no more lost cron mail.
2. The timer — when, /etc/systemd/system/docs-backup.timer (same name, .timer):
[Unit]
Description=Back up ~/documents every night
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
Persistent=true: if the server was off at 02:30, the job runs as soon as it's back.
sudo nano /etc/systemd/system/docs-backup.timer
sudo systemctl daemon-reload
sudo systemctl enable --now docs-backup.timer
systemctl list-timers docs-backup.timer
You enable the timer, not the service — the service has no [Install] section, the timer starts it.
OnCalendar
DayOfWeek Year-Month-Day Hour:Minute:Second — each part may be *, a list 1,15 or a range 9..17:
| OnCalendar | When |
|---|---|
daily | every day at 00:00 |
*-*-* 02:30:00 | every day at 02:30 |
Mon..Fri 09:00 | weekdays at 09:00 |
Sun 03:00 | Sundays at 03:00 |
*-*-01 04:00 | the first of each month |
*:0/15 | every 15 minutes |
Not sure? Ask systemd:
systemd-analyze calendar 'Mon..Fri 09:00'
Original form: Mon..Fri 09:00
Normalized form: Mon..Fri *-*-* 09:00:00
Next elapse: Mon 2026-11-02 09:00:00 CET
Instead of a calendar, a timer can count from something: OnBootSec=15min (after boot), OnUnitActiveSec=1h (an hour after the last run).
cron or a timer?
| cron | systemd timer | |
|---|---|---|
| Set up | one line in crontab -e | two small files |
| Output | mailed, or lost | in the journal |
| Missed while off | skipped | Persistent=true catches up |
| Test it now | run the script | systemctl start NAME.service |
| See the schedule | crontab -l | systemctl list-timers |
💡 For a quick personal job cron is fine. For anything a server depends on — backups, cleanups, reports — a timer gives you logs, status and catch-up for free.