systemd-run lets you spin up systemd units on the fly without needing to create static unit files.
Let’s see it in action. Imagine you need to run a quick script to back up a directory, but you don’t want to clutter your /etc/systemd/system/ with a dedicated unit file for this one-time task.
$ systemd-run --user --on-calendar "Mon,Tue,Wed,Thu,Fri 03:00" --unit backup-home.timer --description "Daily home directory backup" /usr/local/bin/backup-home.sh
This command creates two transient units: backup-home.timer and backup-home.service. The .timer unit is configured to trigger the .service unit at 3 AM, Monday through Friday. The .service unit, in turn, executes /usr/local/bin/backup-home.sh.
When you run systemctl --user list-timers, you’ll see your new timer:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2023-10-30 03:00:00 CEST 2 days left n/a n/a backup-home.timer backup-home.service
And if you want to see the service unit it creates:
$ systemctl --user status backup-home.service
You’ll see something like:
● backup-home.service - Daily home directory backup
Loaded: loaded (/run/user/1000/systemd/generator/backup-home.service; static; vendor preset: enabled)
Active: inactive (dead) since Mon 2023-10-30 09:00:00 CEST; 1 day 15h ago
Main PID: 1234 (code=exited, status=0/SUCCESS)
Oct 30 03:00:00 your-hostname systemd[1000]: Started Daily home directory backup.
Oct 30 03:00:05 your-hostname backup-home.sh[1235]: Starting backup...
Oct 30 03:05:00 your-hostname backup-home.sh[1235]: Backup complete.
The key here is that these units live in /run/user/<UID>/systemd/generator/ (for user units) or /run/systemd/generator/ (for system units) and are managed by systemd’s generator mechanism. They aren’t meant to be permanent.
You can also create on-demand services. For instance, to run a command just once:
$ systemd-run --user --unit my-one-off-task --description "Run a quick check" /usr/bin/my-check-script.sh --arg1 --arg2
This creates my-one-off-task.service. You can then start it immediately:
$ systemctl --user start my-one-off-task.service
Or, if you want it to run at a specific time once:
$ systemd-run --user --on-calendar "2023-10-31 10:00" --unit one-time-report --description "Generate a single report" /opt/scripts/generate_report.py
This creates one-time-report.timer and one-time-report.service. The timer is configured to activate the service exactly once at the specified date and time. After it runs, the timer will be removed.
The power of transient units is in their flexibility for ad-hoc tasks, scheduled jobs that don’t need to persist, or even quickly testing service configurations without touching your main unit files. They are perfect for CI/CD pipelines, administrative scripts, or any situation where you need systemd’s robust process management for a task that’s not part of your core, long-lived services.
The .timer units created by systemd-run are of type oneshot by default, meaning they activate their associated service and then are done. If you need a timer that cycles, you’d typically create a static .timer unit with a [Timer] section specifying OnCalendar= and Persistent=true and then a corresponding .service unit.
You’ll next want to explore how to pass complex arguments or environment variables to your transient services.