Creating a local systemd unit file is how a custom service, timer, socket, path watcher, mount, slice, or target becomes a managed object that the init system can load and activate by name. That matters when the job should survive reboots, follow dependency ordering, and show up through systemctl instead of living as an ad-hoc shell command or boot-script fragment.
A unit file is a plain-text ini-style file with a type-specific extension such as .service, .timer, .socket, .path, .mount, .slice, or .target. Current systemd.unit load-path rules still put administrator-created system units in /etc/systemd/system ahead of /usr/local/lib/systemd/system and /usr/lib/systemd/system, while per-user units belong in /~/.config/systemd/user and are managed with systemctl –user.
The reliable flow is to save the file under the correct manager path, validate it with systemd-analyze verify, reload the manager with systemctl daemon-reload, and then activate the entry-point unit for that design. Keep executable paths absolute, use the type-specific section that matches the filename extension, enable the *.timer, *.socket, or *.path unit instead of its helper service, and expect UnitFileState=static when a helper unit intentionally has no [Install] section.
Related: How to create a systemd service unit
Related: How to create a systemd timer
Related: How to create a systemd socket unit
Related: How to create a systemd path unit
Related: How to create a systemd target unit
[Unit] Description=Create a demo marker for unit-file-create [Service] Type=oneshot ExecStart=/usr/bin/touch /run/demo-unit-created RemainAfterExit=yes [Install] WantedBy=multi-user.target
This example uses a small system service because a *.service file is the simplest way to prove the full create, reload, enable, and verify flow. Use /~/.config/systemd/user plus systemctl –user for a per-user unit, switch the filename suffix and type-specific section for timers, sockets, paths, mounts, or slices, and keep the basename matched when a timer, socket, or path unit activates a companion service. Targets usually use [Unit] plus an optional [Install] section only.
$ sudo systemd-analyze verify /etc/systemd/system/demo-unit.service
No output is the ideal result. systemd-analyze verify also loads referenced units, so read the filename on any warning before assuming the new file is wrong.
$ sudo systemctl daemon-reload
This reruns generators, rereads unit files, and rebuilds the dependency tree. Use systemctl –user daemon-reload for a per-user unit.
$ sudo systemctl enable --now demo-unit.service Created symlink /etc/systemd/system/multi-user.target.wants/demo-unit.service → /etc/systemd/system/demo-unit.service.
This demo activates the service directly because the service itself is the runnable unit. For paired designs, enable the *.timer, *.socket, or *.path unit instead of its helper service, while helper units without [Install] normally stay static and are pulled in by another unit.
$ systemctl show demo-unit.service -p FragmentPath -p LoadState -p ActiveState -p SubState -p Result -p UnitFileState Result=success LoadState=loaded ActiveState=active SubState=exited FragmentPath=/etc/systemd/system/demo-unit.service UnitFileState=enabled
Look for FragmentPath=/etc/systemd/system/demo-unit.service together with LoadState=loaded. This example also shows Result=success plus ActiveState=active and SubState=exited because RemainAfterExit=yes keeps the completed oneshot unit active after the marker file is created.
$ ls -l /run/demo-unit-created -rw-r--r-- 1 root root 0 Apr 22 03:14 /run/demo-unit-created
The marker file proves that the unit did more than load cleanly. Replace this check with the real service log, socket listener, mounted filesystem, queued job, or other job-specific result when adapting the pattern.