Path units are useful when work should start only after a file, directory, or marker path changes. They fit jobs such as reloading an application after a config file update, processing files dropped into a queue directory, or reacting when a flag file appears.

In systemd, a *.path unit monitors one or more absolute paths and activates another unit when the watch condition is met. The upstream systemd.path documentation defines PathExists=, PathChanged=, PathModified=, and DirectoryNotEmpty= as the main triggers, and a path unit starts the matching service with the same basename by default unless Unit= points to a different unit. The example below watches /etc/path-demo/input.txt and starts a small oneshot service named config-watch.service whenever that file changes.

Path units use the kernel inotify mechanism, so they are best for local filesystems and do not reliably detect remote changes made on NFS by another machine. The path unit itself stays in active (waiting) while the triggered oneshot service usually returns to inactive (dead) after a successful run, and fast trigger loops can eventually hit the unit start limits. For per-user watches, place the units under /~/.config/systemd/user and use systemctl --user instead of the system manager commands shown here.

Steps to create a systemd path unit:

  1. Create the file that the path unit will watch.
    $ sudo mkdir -p /etc/path-demo
    $ sudo touch /etc/path-demo/input.txt

    The watched path should exist before normal use so the first change is easy to verify. This example uses a regular file because it makes the PathChanged= trigger easy to demonstrate safely.

  2. Create the service unit that will run when the watch fires.
    [Unit]
    Description=Record changes to /etc/path-demo/input.txt
     
    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c 'date --iso-8601=seconds >> /var/log/config-watch-trigger.log'

    The matching service can run any safe action, such as reloading an application, copying a file, or starting a queue processor. A oneshot service works well when the trigger should perform a short task and exit.

  3. Create the path unit that watches the file and activates the service.
    [Unit]
    Description=Watch /etc/path-demo/input.txt for changes
     
    [Path]
    PathChanged=/etc/path-demo/input.txt
    Unit=config-watch.service
     
    [Install]
    WantedBy=paths.target

    PathChanged= triggers after the file is closed following a write. Use PathExists= when the service should run as soon as a file or directory exists, PathModified= when every write matters, and DirectoryNotEmpty= for queue-style directories. All watched paths must be absolute.

    The upstream systemd.special documentation recommends WantedBy=paths.target for path units that should be active after boot.

  4. Verify that both unit files parse cleanly before reloading the manager.
    $ sudo systemd-analyze verify /etc/systemd/system/config-watch.service /etc/systemd/system/config-watch.path

    No output means systemd accepted the syntax and the unit relationship.

  5. Reload the systemd manager so it notices the new unit files.
    $ sudo systemctl daemon-reload

    This rereads the unit definitions from disk before the new path unit can be enabled or started.

  6. Enable and start the path unit.
    $ sudo systemctl enable --now config-watch.path
    Created symlink /etc/systemd/system/paths.target.wants/config-watch.path -> /etc/systemd/system/config-watch.path.

    The *.path unit is the object to enable. The triggered *.service unit is usually static and is pulled in automatically when the watch condition is met.

  7. Confirm that the path unit is active and waiting for changes.
    $ systemctl status --no-pager --full config-watch.path | head -n 5
    ● config-watch.path - Watch /etc/path-demo/input.txt for changes
         Loaded: loaded (/etc/systemd/system/config-watch.path; enabled; preset: enabled)
         Active: active (waiting) since Mon 2026-04-13 09:00:05 UTC; 9ms ago
       Triggers: ● config-watch.service

    The active (waiting) state is the success condition for the path unit itself. It means systemd is monitoring the configured path and will start the service on the next matching change.

  8. Change the watched file and confirm that the service was triggered.
    $ sudo sh -c 'echo "# change $(date --iso-8601=seconds)" >> /etc/path-demo/input.txt'
    
    $ cat /var/log/config-watch-trigger.log
    2026-04-13T09:00:31+00:00
    
    $ systemctl status --no-pager --full config-watch.service | head -n 4
    ○ config-watch.service - Record changes to /etc/path-demo/input.txt
         Loaded: loaded (/etc/systemd/system/config-watch.service; static)
         Active: inactive (dead) since Mon 2026-04-13 09:00:31 UTC; 388ms ago
    TriggeredBy: ● config-watch.path

    The log file shows that the service ran, while the inactive (dead) state is normal for a successful oneshot service after it exits. If the log stays empty, inspect journalctl -u config-watch.path -u config-watch.service for the real error.