How to Use systemd Timers Instead of Cron in Debian 12 Bookworm

This article provides a step-by-step guide on how to use systemd timers instead of cron in Debian 12 Bookworm.

In traditional Unix-like systems, the cron utility has long been the standard way to schedule recurring tasks. While cron is simple and effective, systemd timers provide a more modern, flexible, and powerful alternative, especially in systems where systemd is the default init system — such as Debian 12 Bookworm.

In this article, we’ll explore how to replace cron jobs with systemd timers, understand how they work, and provide practical examples to help you adopt this method confidently on your Debian 12 system.


Why Use systemd Timers Over Cron?

Before diving into configuration, let’s look at some advantages of using systemd timers over traditional cron:

  • Better logging: systemd integrates with journald, providing centralized and detailed logs.
  • Dependency management: Timers can be linked to other systemd services, allowing complex orchestration.
  • Accurate scheduling: systemd timers allow monotonic time-based execution and calendar-based events.
  • Job tracking: You can check when a job last ran, when it will run again, and if it failed.
  • User-based timers: Like cron, users can set up timers without needing superuser privileges.

Step-by-Step Guide: Replacing Cron with systemd Timers

Let’s walk through replacing a cron job with a systemd timer. We’ll start from scratch.


Example Task: Log the Current Date Every Hour

We’ll simulate a cron job that logs the current date and time to a file every hour.


Step 1: Create a systemd Service Unit

Unlike cron jobs, systemd separates the action (what to do) and the schedule (when to do it). First, we’ll define a service that executes the command.

Create a new service file, e.g., /etc/systemd/system/log-date.service.

[Unit]
Description=Log current date and time to /var/log/date.log

[Service]
Type=oneshot
ExecStart=/usr/bin/date >> /var/log/date.log

Explanation:

  • Type=oneshot: This tells systemd that the command runs once and exits.
  • ExecStart: Specifies the command to run. In this case, we append the current date to a log file.

Step 2: Create the Timer Unit

Now let’s create the timer file: /etc/systemd/system/log-date.timer.

[Unit]
Description=Run log-date.service every hour

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

Explanation:

  • OnCalendar=hourly: This schedules the job to run at the start of every hour. You can customize this to your needs (more on that later).
  • Persistent=true: Ensures that the job runs immediately on boot if it was missed while the system was off.
  • WantedBy=timers.target: Ensures the timer starts automatically on boot when enabled.

Step 3: Enable and Start the Timer

To activate the timer, run the following:

sudo systemctl daemon-reload
sudo systemctl enable --now log-date.timer

Check if the timer is active:

systemctl list-timers

This will display all active timers, their last and next runtime, and associated service units.


Step 4: View Logs

One major advantage of systemd timers is access to detailed logs:

journalctl -u log-date.service

This shows output and errors from the last runs of the service.


Using User-Level Timers

Just like crontab -e allows individual users to set up cron jobs, users can also manage their own timers.

Here’s how a non-root user can create a timer:

  1. Create directories (if they don’t exist):
mkdir -p ~/.config/systemd/user
  1. Create a service file, e.g., ~/.config/systemd/user/mytask.service:
[Unit]
Description=User task example

[Service]
Type=oneshot
ExecStart=/usr/bin/notify-send "Time to take a break!"
  1. Create a timer file, e.g., ~/.config/systemd/user/mytask.timer:
[Unit]
Description=Notify break time every 2 hours

[Timer]
OnUnitActiveSec=2h
Unit=mytask.service

[Install]
WantedBy=default.target
  1. Reload user systemd daemon and enable the timer:
systemctl --user daemon-reexec
systemctl --user enable --now mytask.timer
  1. View user timers:
systemctl --user list-timers

Note: Ensure your user session is enabled for lingering if you want timers to persist outside login sessions:

sudo loginctl enable-linger yourusername

Customizing Timer Schedules

systemd timers provide powerful scheduling options beyond cron:

Examples of OnCalendar Values

Timer ExpressionDescription
OnCalendar=dailyEvery day at midnight
OnCalendar=weeklyEvery week on Monday at 00:00
OnCalendar=monthlyFirst day of the month at 00:00
OnCalendar=*-*-01 12:00Every month on the 1st at noon
OnCalendar=Mon *-*-* 09:00Every Monday at 9am
OnCalendar=2025-05-01 10:00:00One-time run on May 1, 2025 at 10am

You can even specify multiple schedules:

OnCalendar=Mon,Fri 12:00

Comparing Cron vs systemd Timers

Featurecronsystemd timers
LoggingLimited, needs manual setupBuilt-in with journald
SyntaxCrontab-specific syntaxHuman-readable OnCalendar
DependenciesNoneCan depend on services or other units
Missed JobsSkippedCan run missed jobs on boot
User AccessYes (with crontab)Yes (with --user)
Timer TypesTime-based onlyTime-based and monotonic
Job StatusNo built-in status trackingsystemctl list-timers shows all

Tips and Best Practices

  1. Test your service manually before enabling the timer:
sudo systemctl start log-date.service
  1. Use Persistent=true for important tasks that must run even if the system was off during the scheduled time.

  2. Use monotonic timers (OnBootSec, OnActiveSec) for tasks relative to system uptime (e.g., post-boot actions).

  3. Use descriptive unit names and place them in /etc/systemd/system/ or ~/.config/systemd/user/ depending on system or user context.


Disabling and Removing Timers

To disable and stop a timer:

sudo systemctl disable --now log-date.timer

To completely remove it:

sudo rm /etc/systemd/system/log-date.timer
sudo rm /etc/systemd/system/log-date.service
sudo systemctl daemon-reload

Conclusion

While cron remains a simple and widely-used tool for scheduling, systemd timers offer a modern, integrated, and highly configurable approach, especially for Debian 12 Bookworm users. They provide better logging, more readable time expressions, and native integration with the rest of the systemd ecosystem.

Once you get comfortable with the structure of .service and .timer files, you’ll find that systemd timers are not only powerful but often easier to manage and troubleshoot than traditional cron jobs.

So the next time you’re writing a script to run on a schedule — whether every 10 minutes or every Monday — consider giving systemd timers a try.