
In modern Linux systems, systemd has become the standard init system and service manager. While many of us are familiar with using cron for scheduling tasks, systemd timers offer a more powerful, flexible, and integrated alternative. In this blog, we’ll dive into what systemd timers are, why you might want to use them, and how to set them up with practical examples.
What Makes systemd Timers Special?
Whether you’re running daily backups, cleaning up logs every week, or launching a service right after boot, automation is key. While cron has served us well for decades, systemd timers bring automation into the modern Linux era, with more control, better logging, and seamless integration into the system.
Think of systemd timers as cron jobs with superpowers.
Why systemd Timers > cron
You’re not just setting a clock — you’re designing automated, event-driven tasks with intelligence. This blog is your all-in-one guide to:
- Creating powerful timers from scratch
- Migrating old cron jobs into sleek .service + .timer combos
- Testing, monitoring, and troubleshooting your automation
- Managing missed events, reboots, dependencies, and more
Whether you’re a sysadmin, developer, or DevOps engineer, systemd timers help you sleep better, knowing your tasks will always run (even if your system rebooted last night)
REQUIREMENTS
Before you start using systemd timers, ensure the following:
- Basic understanding of systemd: You should be familiar with how unit files work, especially .service units.
- Root or sudo privileges: Required to create or manage system-level timers in /etc/systemd/system/.
- User-level alternatives: If you don’t have root access, you can create timers under ~/.config/systemd/user/.
- Access to a text editor, Such as Vim, nano, or Code (VS Code), to create and edit unit files.
- systemd version 219 or later: Most features like OnCalendar, RandomizedDelaySec, and Persistent are supported from version 219 onwards (RHEL 7+, Ubuntu 16.04+, etc.).
- Writable access to the directory where your .service and .timer files will be placed.
- Executable script or command: The timer needs to trigger something — make sure the script (e.g., /usr/local/bin/myscript.sh) exists and has +x permissions.
The systemd timer concept
Systemd timer units provide a mechanism for scheduling jobs on Linux. The execution time of these jobs can be based on the time and date or events. The .timer file name extension identifies Systemd timer units. Each timer file requires a corresponding service file that it controls. In other words, a timer file activates and manages the corresponding service file. Systemd timers support the following features:
- Jobs scheduled using a timer unit can depend on other systemd services. Timer units are treated as regular systemd services, so they can be managed with systemctl.
- Timers can be real-time (being triggered on calendar events) or monotonic (being triggered at a specified time elapsed from a certain starting point).
- Time units are logged to the system journal, which makes it easier to monitor and troubleshoot them.
- Timers use the centralized systemd management services.
- If the system is off during the expected execution time, the timer is executed once the system is running again.
systemd Timers vs cron Jobs
When it comes to task scheduling in Linux, cron has long been the go-to tool. But with the evolution of systemd, a more modern and integrated alternative has emerged: systemd timers. So, which one should you use? Let’s break it down with a fun and practical comparison:
| Feature | Cron jobs | Systemd timers |
| Logging | Basic (uses email or syslog) | Advanced with journalctl |
| Dependencies | Not supported | Full control with After=, Requires= |
| Missed run handling | Skipped silently | Persistent=true to catch up |
| Granularity | Minute-level only | Flexible: seconds, boot, calendar |
| Random delay | Not possible | RandomizedDelaySec for load spread |
| Integration | Standalone tool | Built-in systemd component |
| Security context | Limited runs as a user | Fine-grained control over user/group |
| System awareness | No context of services | Aware of the system state, targets |
| User-level configuration | Yes (crontab -e) | Yes (~/.config/systemd/user/) |
| Ease of use | Aware of the system state, targets | Limited runs as a user |
Summary: If you’re automating a quick script or running something simple once an hour, cron still does the job. However, for tasks that are part of a larger system, require logs, retries, or service awareness, systemd timers are your best option.
Use cron for simple jobs on legacy systems. Use systemd timers for anything needing precision, logging, and better integration with modern Linux systems.
Timer Unit and Service Unit
A timer unit schedules when a service unit runs. Typically, you’ll have two files:
- mytask.service — Defines the actual task.
- mytask.timer — Defines when the task runs.
1. Creating a timer
The following example shows how to set up a timer that triggers the helloworld.sh shell script after boot time and repeats its execution every 24 hours relative to its activation time. It also runs Monday to Friday at 10 a.m.
Example1:
1. Create the file /etc/systemd/system/helloworld.service with the following content:
[Unit]
Description=”Hello World script”
[Service]
ExecStart=/usr/local/bin/helloworld.sh
This is a systemd service file that tells systemd which application to run.
Description for helloworld.service
- A brief description explaining the service file’s purpose.
- The application to execute.
The [Unit] and [Service] sections are the minimum sections required for a service file to work. Systemd service files normally contain an [Install] section that determines one or more targets for a service to load. This section is not required in service files for timers, since this information is provided with the timer file.
2. Create the file /etc/systemd/system/helloworld.timer with the following content:
[Unit]
Description=”Run helloworld.service 5min after boot and every 24 hours relative to activation time”
[Timer]
OnBootSec=5min
OnUnitActiveSec=24h
OnCalendar=Mon..Fri *-*-* 10:00:*
Unit=helloworld.service
[Install]
WantedBy=multi-user.target
This is the timer file that controls the activation of the respective service file.
Description for helloworld.timer
- A brief description explaining the timer file’s purpose.
- Specifies a timer that triggers the service five minutes after the system boots. See Monotonic timers for details.
- Specifies a timer that triggers the service 24 hours after the service has been activated (that is, the timer triggers the service once a day). See Real-time timer for details.
- Specifies a timer that triggers the service at fixed points in time (in this example, Monday to Friday at 10 a.m.). See Real-time timer for details.
- The service file to execute.
- The systemd target in which the timer gets activated.
3. Verify that the files you created above contain no errors:
systemd-analyze verify /etc/systemd/system/helloworld.*
If the command returns no output, the files have passed the verification successfully.
4. Start the timer:
sudo systemctl start helloworld.timer
Activates the timer for the current session only.
5. Enable the timer to make sure that it is activated on boot:
sudo systemctl enable helloworld.timer
2. Steps to Create helloworld.sh Script
To run the service file, we just need to do one more step here, which is creating a script.
Step 1: Create the Script File
Use your preferred editor (like nano) to create the file:
sudo nano /usr/local/bin/helloworld.sh
Paste the following content into the file:
#!/bin/bash
echo “Hello, World! from systemd at $(date +”%A %d %B %Y %I:%M:%S %p %Z”)” >> /var/log/helloworld.log
This command appends the current date and time in your desired format to the file /var/log/helloworld.log
Step 2: Save and Exit
In nano, press Ctrl + O → Enter to save.
Then Ctrl + X to exit.
Step 3: Make the Script Executable
Set the executable permission using:
sudo chmod +x /usr/local/bin/helloworld.sh
This is essential — without this step, systemd will fail to run the script with an “Exec format error” or “permission denied”.
Step 4: Verify
Check that the file is executable:
ls -l /usr/local/bin/helloworld.sh
You should see something like:
-rwxr-xr-x 1 root root 120 Jul 13 12:35 /usr/local/bin/helloworld.sh
The x in -rwxr-xr-x confirms it’s executable.
Step 5: Test It Manually
Run the script directly to test:
sudo /usr/local/bin/helloworld.sh
Then check:
cat /var/log/helloworld.log
You should see a log entry like:
Hello, World! from systemd at Sunday 13 July 2025 12:40:00 PM IST
3. Reloading and Enabling in systemd
- sudo systemctl daemon-reload : This is required after editing either a .timer or a .service file, because systemd caches unit definitions.
- sudo systemctl enable <unit>.timer : This sets it to start at boot. Do this only once, not every time you edit.
- sudo systemctl start <unit>.timer : Start the unit if you want it to run immediately
4. Managing timers
You can manage timers using the systemctl command.
Starting and stopping timers
- sudo systemctl start TIMER.timer
- sudo systemctl restart TIMER.timer
- sudo systemctl stop TIMER.timer
Enabling and disabling timers
- sudo systemctl enable TIMER.timer
- sudo systemctl disable TIMER.timer
Showing the timer file contents
- sudo systemctl cat TIMER.timer
Checking on a specific timer status
rajseharann@genexdbs:/etc/systemd/system$ systemctl status helloworld.timer
● helloworld.timer – “Run helloworld.service 5min after boot and every 24 hours relative to activation time”
Loaded: loaded (/etc/systemd/system/helloworld.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Sun 2025-07-13 12:44:18 IST; 32min ago
Trigger: Mon 2025-07-14 12:39:00 IST; 23h left
Triggers: ● helloworld.service
Jul 13 12:44:18 genexdbs systemd[1]: Started “Run helloworld.service 5min after boot and every 24 hours relative to activation time”.
Timer Info – Shows the timer’s name and its description.
- Load State – Tells whether the timer is loaded, its file path, and if it’s enabled to run at boot.
- Active Status – Indicates if the timer is active and how long it has been active.
- Next Trigger – Displays when the timer will next activate the service.
- Triggered Service – Shows which
.serviceunit the timer will start. - Documentation – Points to related docs (like man pages), or stays empty if none.
- Last Log Entry – Shows the most recent log message related to the timer.
To list all the timers available on the system by using this:
- active–>sudo systemctl list-timers
- inactive–>sudo systemctl list-timers –all
To list all timers matching a pattern:
- sudo systemctl list-timers PATTERN
- sudo systemctl list-timers–allPATTERN
PATTERN must be a name or a shell globbing expression. The operators *, ?, and [] may be used. Refer to man 7 glob for more information on globbing patterns.
To list timers matching a certain state:
- sudo systemctl list-timers–state=STATE
STATE takes the following values: active, failed, load, sub. See man systemctl for details.

In the above screenshot, we can see a list of timers available in the system, and we can check the specific timer as well.
5. Timer types
systemd supports two types of timers: real-time (based on calendar) and monotonic (based on events). Although timers are normally persistent, systemd also allows setting up transient timers that are only valid for the current session.
5.1 Real-time timer
Real-time timers are triggered by calendar events. They are defined using the option OnCalendar.
You can specify when to trigger an event based on date and time. Use the following template:
OnCalendar=DayOfWeek Year-Month-Day Hour:Minute:Second
- Day of week. Possible values are Sun, Mon, Tue, Wed, Thu, Fri, Sat. Leave out to ignore the day of the week.
- Date. Specify month and day by two digits, year by four digits. Each value can be replaced by the wildcard * to match every occurrence.
- Time. Specify each value by two digits. Each value can be replaced by the wildcard * to match every occurrence.
- Applies to all values: Use two dots to define a continuous range (Mon..Fri). Use a comma to delimit a list of separate values (Mon,Wed,Fri).
Examples:
- 6 p.m. every Friday: OnCalendar=Fri *-*-* 18:00:00
- 1 a.m. and 3 a.m. on Sundays and Tuesdays: OnCalendar=Tue,Sun *-*-* 01,03:00:00
- To specify triggers at different times, you can create more than one OnCalendar entry in a single timer file: OnCalendar=Mon..Fri *-*-* 10:00 OnCalendar=Sat,Sun *-*-* 22:00
For a full list of available features and options, refer to man 7 systemd.time, which offers additional information.
5.2 Monotonic timers
Monotonic timers are triggered at a specified time elapsed from a certain event, such as a system boot or system unit activation event. Values are defined as time units (minutes, hours, days, months, years, etc.). The following units are supported: usec, msec, seconds, minutes, hours, days, weeks, months, years. There are several options for defining monotonic timers:
- OnActiveSec: time after unit activation OnActiveSec=50minutes
- OnBootSec: time after system boot OnBootSec=10hours
- OnStartupSec: time after the service manager is started. For system services, this is almost equal to OnActiveSec. Use this for user services where the service manager is started at user login. OnStartupSec=5minutes 20seconds
- OnUnitActiveSec: time after the corresponding service was last activated. OnUnitActiveSec=10seconds
- OnUnitInactiveSec: time after the corresponding service was last deactivated. OnUnitInactiveSec=2 hours 15 minutes 18 seconds
5.3 Transient timers
Transient timers are temporary timers that are only valid for the current session. Using these timers, you can either use an existing service file or start a program directly. Transient timers are invoked by running systemd-run.
- The following example runs the helloworld.service unit every two hours: sudo systemd-run –on-active=”2hours” –unit=”helloworld.service”
- To run a command directly, use the following syntax. In this example, the script /usr/local/bin/helloworld.sh is called directly: sudo systemd-run–on-active=”2hours” /usr/local/bin/helloworld.sh
- If the command takes parameters, add them separated by space: sudo systemd-run –on-active=”2hours” /usr/local/bin/helloworld.sh –language=pt_BR
- Transient timers can be monotonic or real-time. The following switches are supported and work as described in Monotonic timers: –on-active –on-startup –on-unit-active –on-unit-inactive –on-calendar
- For more information, refer to man 1 systemd-run.
6. Troubleshooting errors
6.1 Avoiding errors:
- To avoid errors with systemd timers, make sure to follow these best practices:
- Verify that the executable you specify in the service with ExecStart runs correctly.
- Check the syntax of the service and timer files by running systemd-analyze verify FILE.
- Check execution times of calendar entries by running systemd-analyze calendar CALENDAR_ENTRY.
6.2 Event is not triggered:
When you activate a timer that contains non-critical errors, systemd silently ignores them. For example:
Example: systemd timer file cutout containing a non-fatal error
[Timer]
OnBootSec=5min
OnClendar=Mon..Fri 10:00
Unit=helloworld.service
Line 3 contains a syntax error (OnCalendar instead of OnCalendar). Since the [Timer] section contains a second timer entry (OnBoot), the error is not critical and is silently ignored. As a consequence, the Monday to Friday trigger is not executed. The only way to detect the error is to use the command systemd-analyze verify:
systemd-analyze verify /etc/systemd/system/helloworld.timer
/etc/systemd/system/helloworld.timer:7: Unknown key name ‘OnClendar’ in section ‘Timer’, ignoring.
6.3 Checking the system journal for errors:
As with every systemd service, events and actions triggered by timers are logged with the system journal. If a trigger does not behave as expected, check the log messages with journalctl. To filter the journal for relevant information, use the -u switch to specify the systemd timers and service files. Use this option to show the log entries for the timer and the corresponding service file:
sudo journalctl -u helloworld.timer -u helloworld.service
- or shorter (if applicable): sudo journalctl -u helloworld.*
- Watch Logs in Real Time journalctl -u clear-cache.service -f
- Verify with systemd-analyze verify systemd-analyze verify /etc/systemd/system/clear-cache.service
journalctl is a tool that supports many options and filters. Please refer to man 1 journalctl for in-depth information. The following options are useful for troubleshooting timers.
6.4 systemd timer: catching up on missed runs:
If a systemd timer was inactive or the system was off during the expected execution time, missed events can optionally be triggered immediately when the timer is activated again. To enable this, add the configuration option Persistent=true to the [Timer] section:
[Timer]
OnCalendar=Mon..Fri 10:00
Persistent=true
Unit=helloworld.service
A few more examples:
Example 1: Clear System Cache Weekly
/etc/systemd/system/clear-cache.service
[Unit]
Description=Clear system cache
[Service]
Type=oneshot
ExecStart=/usr/bin/sync; echo 3 > /proc/sys/vm/drop_caches
/etc/systemd/system/clear-cache.timer
[Unit]
Description=Weekly cache cleanup every Sunday at 2 AM
[Timer]
OnCalendar=Sun *-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
Example 2: Monitor Disk Space Every 15 Minutes
/etc/systemd/system/disk-check.service
[Unit]
Description=Log disk usage
[Service]
Type=oneshot
ExecStart=/usr/bin/df -h > /var/log/disk-usage.log
/etc/systemd/system/disk-check.timer
[Unit]
Description=Disk space check every 15 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=15min
[Install]
WantedBy=timers.target
References
https://documentation.suse.com/smart/systems-management/html/systemd-working-with-timers/index.html#systemd-timer-types-monotonic: Timing is Everything: A Deep Dive into systemd Timers