How file system event APIs differ between Linux and macOS, and why it matters for cross-platform tooling.
When building config-pilot's live reload feature, I needed file system events on both Linux and macOS. The two APIs are more different than I expected.
inotify is a kernel subsystem that lets you watch files and directories for events.
# Verify inotify is available
cat /proc/sys/fs/inotify/max_user_watchesKaranveer Singh Shaktawat
Full Stack Engineer & Infrastructure Architect
Building portfolio, contributing to open source, and seeking remote full-time roles with significant technical ownership.
Pick what you want to hear about — I'll only email when it's worth it.
Did this resonate?
One changed line in a Dockerfile invalidates every layer after it. Ordering your Dockerfile with this in mind cuts rebuild times dramatically.
git worktree lets you have multiple working trees from one repo — no stashing, no switching, no friction.
// In Rust, using the notify crate
use notify::{Watcher, RecursiveMode, watcher};
let (tx, rx) = std::sync::mpsc::channel();
let mut watcher = watcher(tx, Duration::from_millis(100)).unwrap();
watcher.watch("/etc/nginx/nginx.conf", RecursiveMode::NonRecursive).unwrap();inotify is event-based and precise: you get specific events (IN_MODIFY, IN_CLOSE_WRITE, IN_ATTRIB). The limit on watched files is configurable via /proc/sys/fs/inotify/max_user_watches.
FSEvents is a higher-level API that coalesces events. It's designed for watching directory trees, not individual files.
Key difference: FSEvents does not give you individual file-level events reliably. It tells you "something changed in this directory." You then have to stat the directory yourself to find what.
IN_CLOSE_WRITE on Linux fires when a file is closed after being written — exactly what you want for config file changes. FSEvents doesn't have an equivalent. You get a directory change event and have to compare mtimes.
The notify crate in Rust abstracts this, but understanding the underlying APIs explains why the behavior sometimes differs on cross-platform tools. Live reload that works perfectly on Linux can miss events on macOS if you're not accounting for FSEvents' coalescing behavior.
Practical fix: on macOS, stat the watched path after every FSEvents callback and compare modification time. Don't assume the event itself tells you what changed.