A systemd timer runs scheduled maintenance, report generation, or short automation jobs without leaving recurring work split between shell loops, ad-hoc scripts, and old cron fragments. Keeping the schedule as a managed unit makes the job visible through systemctl and journalctl, which simplifies enablement, troubleshooting, and boot-time behavior.
A *.timer unit activates another unit at a wall-clock or monotonic interval. Current upstream systemd.timer documentation states that a timer starts the service with the same basename by default, while Unit= can point at a different unit when needed. Calendar timers created with OnCalendar= are also ordered after time-set.target and time-sync.target, and boot-enabled timers are normally attached through timers.target.
The example below creates a small oneshot service named systemd-timer-demo.service and a matching timer that fires at the start of each minute so the result can be verified quickly. System-level timers belong under /etc/systemd/system and need root access, repeating timers should not target services that stay active through RemainAfterExit=yes, and the example sets AccuracySec=1s because the upstream default is 1min, which can delay the visible run during a demo.
Steps to create a systemd timer:
- Open a terminal session with an account that can use sudo.
For a per-user timer, place both unit files under ~/.config/systemd/user and replace the sudo systemctl commands below with systemctl –user.
- Create the service unit that the timer will trigger.
[Unit] Description=Append the current time to /var/log/systemd-timer-demo.log [Service] Type=oneshot ExecStart=/bin/sh -c 'date --iso-8601=seconds >> /var/log/systemd-timer-demo.log'
Timers commonly trigger short oneshot services that do one task and then exit. If the target service already exists, keep its real unit name and make the timer match that basename or add Unit= in the timer file.
Related: How to create a systemd service unit
- Create the timer unit file.
[Unit] Description=Run systemd-timer-demo.service every minute [Timer] OnCalendar=*-*-* *:*:00 AccuracySec=1s Persistent=true [Install] WantedBy=timers.target
OnCalendar=*-*-* *:*:00 fires at the start of every minute. Replace that expression with the real schedule after the demo flow is understood.
AccuracySec=1s keeps the test run close to the scheduled second. Without that override, the upstream default AccuracySec=1min allows the manager to coalesce wake-ups inside a one-minute window.
Persistent=true catches up one missed run after downtime, but only for timers that use OnCalendar=.
- Verify that both unit files parse cleanly.
$ sudo systemd-analyze verify /etc/systemd/system/systemd-timer-demo.service /etc/systemd/system/systemd-timer-demo.timer
No output is the ideal result. Current systemd-analyze verify behavior can also report warnings from some other loaded unit file, so read the filename on each message before assuming the new timer is wrong.
- Preview the calendar expression before enabling the timer.
$ systemd-analyze calendar '*-*-* *:*:00' Normalized form: *-*-* *:*:00 Next elapse: Mon 2026-04-13 21:40:00 +08 (in UTC): Mon 2026-04-13 13:40:00 UTC From now: 12s leftsystemd-analyze calendar is the safest way to confirm what OnCalendar= actually means before the unit starts firing on a real host.
- Reload the systemd manager so it notices the new unit files.
$ sudo systemctl daemon-reload
This reloads the unit definitions from disk and rebuilds the dependency tree before enablement or manual starts.
- Enable the timer for boot and start it immediately.
$ sudo systemctl enable --now systemd-timer-demo.timer Created symlink /etc/systemd/system/timers.target.wants/systemd-timer-demo.timer → /etc/systemd/system/systemd-timer-demo.timer.
Enable the *.timer unit, not the triggered *.service unit. The service itself normally remains static and is started by the timer when the schedule elapses.
- Confirm that the timer is loaded and waiting for its next run.
$ systemctl status --no-pager --full systemd-timer-demo.timer | sed -n '1,8p' ● systemd-timer-demo.timer - Run systemd-timer-demo.service every minute Loaded: loaded (/etc/systemd/system/systemd-timer-demo.timer; enabled; preset: enabled) Active: active (waiting) since Mon 2026-04-13 21:39:47 +08; 5ms ago Trigger: Mon 2026-04-13 21:40:00 +08; 12s left Triggers: ● systemd-timer-demo.service Apr 13 21:39:47 host systemd[1]: Started systemd-timer-demo.timer - Run systemd-timer-demo.service every minute.The timer success state is Loaded: loaded (…; enabled…) together with Active: active (waiting) and a future Trigger: timestamp.
- Confirm the next scheduled run in the timer table.
$ systemctl list-timers --all systemd-timer-demo.timer --no-pager NEXT LEFT LAST PASSED UNIT ACTIVATES Mon 2026-04-13 21:40:00 +08 12s - - systemd-timer-demo.timer systemd-timer-demo.service 1 timers listed.
Before the first execution, LAST and PASSED stay empty. After the timer fires once, both columns show the most recent activation time.
- Wait until the next scheduled minute and confirm that the service actually ran.
$ cat /var/log/systemd-timer-demo.log 2026-04-13T21:40:00+08:00 $ systemctl status --no-pager --full systemd-timer-demo.service | sed -n '1,7p' ○ systemd-timer-demo.service - Append the current time to /var/log/systemd-timer-demo.log Loaded: loaded (/etc/systemd/system/systemd-timer-demo.service; static) Active: inactive (dead) since Mon 2026-04-13 21:40:00 +08; 56s ago TriggeredBy: ● systemd-timer-demo.timer Process: 2930 ExecStart=/bin/sh -c date --iso-8601=seconds >> /var/log/systemd-timer-demo.log (code=exited, status=0/SUCCESS) Main PID: 2930 (code=exited, status=0/SUCCESS)A successful oneshot service usually returns to inactive (dead) after it exits. The timestamp in the log file is the proof that the timer activated the service on schedule.
If the log file stays empty or the service status changes to failed, inspect the recent journal with sudo journalctl -u systemd-timer-demo.timer -u systemd-timer-demo.service -n 20 --no-pager.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
