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.

Want structured learning?

Take the full Systemd course →