Files
swift-inotify/Sources/Inotify/Inotify.docc/WatchingDirectoryTrees.md
T
T. R. Bernstein 134034f3ea Watch directories moved into the tree and report their content
Automatic subtree watching only reacted to `CREATE`, so a directory
moved in from elsewhere stayed unwatched. It is now handled like a
created one. Items that already exist in such a directory never
produce kernel events; they are reported with the same event kind
and `synthesized` set to `true`, so consumers can treat them as
newly appeared.
2026-09-13 23:13:32 +02:00

2.8 KiB

Watching Directory Trees

Monitor an entire directory hierarchy for filesystem events.

Overview

The Linux inotify API watches individual directories — it does not descend into subdirectories automatically. The Inotify/Inotify actor offers two convenience methods that handle the recursion for you.

Recursive Watch

Call Inotify/Inotify/addRecursiveWatch(forDirectory:mask:) to walk the directory tree once and install a watch on every subdirectory that exists at the time of the call:

let inotify = try Inotify()
let descriptors = try await inotify.addRecursiveWatch(
    forDirectory: "/home/user/project",
    mask: [.create, .modify, .delete]
)

The returned array contains one watch descriptor per directory. Subdirectories created after this call are not covered.

Automatic Subtree Watching

When you also want future subdirectories to be picked up, use Inotify/Inotify/addWatchWithAutomaticSubtreeWatching(forDirectory:mask:) instead:

let descriptors = try await inotify.addWatchWithAutomaticSubtreeWatching(
    forDirectory: "/home/user/project",
    mask: [.create, .modify, .delete]
)

Internally this listens for CREATE and MOVED_TO events carrying the InotifyEventMask/isDir flag and installs new watches with the same mask on the subdirectory and its subtree whenever one appears. Items that already exist inside such a subdirectory are reported with InotifyEvent/synthesized set to true, since the kernel never produces events for them; a synthesized event may duplicate a kernel event for the same item.

When a directory is moved out of the watched tree, the watches on it and on its subdirectories are removed, so no events are reported under the stale path.

Excluding Directories

When watching large trees you often want to skip certain subdirectories entirely — version-control metadata, build artefacts, dependency caches, and so on. Call Inotify/Inotify/exclude(names:) before adding a recursive or automatic-subtree watch:

let inotify = try Inotify()
await inotify.exclude(names: ".git", "node_modules", ".build")

try await inotify.addWatchWithAutomaticSubtreeWatching(
    forDirectory: "/home/user/project",
    mask: .allEvents
)

Excluded names are matched against the last path component of each directory during resolution and are also filtered from the event stream, so you never receive events for items whose name is on the exclusion list.

Choosing the Right Method

Method Covers existing subdirectories Covers new subdirectories
Inotify/Inotify/addWatch(path:mask:) No No
Inotify/Inotify/addRecursiveWatch(forDirectory:mask:) Yes No
Inotify/Inotify/addWatchWithAutomaticSubtreeWatching(forDirectory:mask:) Yes Yes