Timers and operations
Run transient work
Use systemd-run for one-off or temporary work that still needs logs, limits, and lifecycle tracking.
systemd-run creates a transient unit: a service that exists only while it runs, with no unit file on disk. You get all the machinery of a service, journal capture, resource limits, and cgroup tracking, for a command you will run once.
Let’s start with a harmless one:
systemd-run --user --wait /usr/bin/true
Running as unit: run-r1f3a2b9c4d.service; invocation ID: 7b0f...
Finished with result: success
Main processes terminated with: code=exited, status=0/SUCCESS
Service runtime: 4ms
--wait makes the command block until the unit finishes, then print the result. --user runs it in your own user manager, so no root is needed. systemd invented the unit name for us. Pass --unit= when you want a name you can remember.
Where this earns its keep
A transient service shines for an administrative command that needs resource controls or journal capture.
Say you need to rebuild a search index. It eats memory, and you refuse to let it take down the API running on the same box. Give it a name and a ceiling:
sudo systemd-run --unit=reindex -p MemoryMax=1G -p CPUQuota=50% \
/usr/local/bin/reindex-search
-p sets any unit property, the same ones you would write in a [Service] section. The job now has a name, a memory ceiling, half a CPU, and its output lands in the journal. You can check on it like any other service:
systemctl status reindex.service
journalctl -u reindex.service -f
Compare that with running the script from your shell. No limits. Output lost when your SSH session drops. And the process dies with the session unless you remembered nohup or tmux. I have lost a long-running job to a flaky Wi-Fi connection more than once. systemd-run fixes all three problems with one flag.
Scopes for interactive work
A transient scope is the other variant. systemd-run --scope places a command under systemd management while it stays attached to your terminal:
systemd-run --user --scope -p MemoryMax=2G npm run build
You still see the output and can still press Ctrl+C. But the build now runs in its own cgroup with a memory limit. Useful when you want limits on something interactive.
The cleanup gotcha
Successful transient units vanish when they finish. Failed ones stay visible in systemctl --failed until you clear them:
systemctl reset-failed reindex.service
That is a feature. The failure evidence survives so you can read the journal. But it surprises people who expect “transient” to mean “traceless”.
Try the --user --wait example above, then run systemctl --user status and see what remains. Then decide the boundary for yourself. My rule: anything I run twice, or that a teammate must find and understand later, gets a permanent unit file. Everything else is a good fit for systemd-run.
Lesson completed