fsnotify
A Go library that delivers cross-platform filesystem change notifications through a single Watcher API backed by native OS event mechanisms.
Repository Health
Technical Analysis
fsnotify wraps the filesystem-change primitives of Linux (inotify), macOS/BSD (kqueue), Windows (ReadDirectoryChangesW), and illumos (FEN) behind one consistent Go API: create a Watcher, add paths, and read Create/Write/Remove/Rename/Chmod events off a channel. It has been the de facto standard for filesystem watching in the Go ecosystem for over a decade and sits as an indirect dependency inside a huge share of the Go tooling landscape — build tools, hot-reloaders, config watchers, and CLI utilities.
The library deliberately stays small: no recursive watching, no polling fallback, no bundled debouncing. Instead it gives callers a thin, predictable layer over what each operating system actually reports, along with extensive documentation of the platform-specific quirks (rename cookies, Chmod-before-Remove ordering on Linux, kqueue file-descriptor limits) that trip up naive implementations. Consumers who need higher-level behavior like recursive watches or event coalescing are expected to build it on top.
What You Get
- A
Watchertype withAdd/AddWith/Remove/Close/WatchListmethods and buffered or unbufferedEvents/Errorschannels - A unified
Opbitmask (Create,Write,Remove,Rename,Chmod) that normalizes each OS’s native event vocabulary - Per-platform backends (inotify, kqueue, ReadDirectoryChangesW, FEN) selected automatically at build time via Go build tags
AddWith/WithBufferSizefor tuning the Windows event buffer when large bursts risk overflowFSNOTIFY_DEBUG=1environment-variable support that prints every raw platform event to stderr for troubleshooting- Extensive documented platform notes covering rename-cookie pairing, Linux’s Chmod-before-Remove ordering, and kqueue file-descriptor exhaustion
Common Use Cases
- Hot-reloading build tools - watch source files and trigger a rebuild or live-reload on Write/Create events, the pattern used by many Go-based dev servers and static-site generators
- Configuration hot-reload - watch a config file’s parent directory and re-read settings when editors atomically replace the file via a Rename
- File-sync and backup daemons - detect Create/Remove/Rename events in a watched tree to queue sync operations without polling
- Log and data pipeline tailers - notice when new files appear in a spool directory and start processing them immediately
- Editor and IDE tooling - detect external file changes (e.g. git checkout, formatter output) to refresh in-memory buffers or trigger diagnostics
Under The Hood
Architecture
fsnotify is organized around one exported Watcher struct that embeds a backend interface (Add, AddWith, Remove, WatchList, Close, xSupports) defined in fsnotify.go; the concrete implementation is chosen entirely at compile time through Go build tags, with backend_inotify.go (//go:build linux), backend_kqueue.go (macOS/BSD), backend_windows.go, and backend_fen.go (illumos) each providing their own struct that satisfies that interface and embeds a shared *shared helper type for common bookkeeping like watch bookkeeping and channel wiring. This keeps the public surface (NewWatcher, Add, Events, Errors, Close) identical across platforms while letting each backend manage OS-specific state — inotify’s rename-cookie LRU cache, kqueue’s per-file descriptor table, Windows’s overlapped I/O buffer — internally. Because the abstraction boundary is a plain Go interface rather than a runtime dispatch table, swapping or extending a backend only touches its own file; the core fsnotify.go and internal/ package never need to know which OS backend is active.
Tech Stack
The module (go.mod) targets Go 1.23+ and declares a single external dependency, golang.org/x/sys, used for the raw syscalls each backend needs (unix.InotifyInit1, kqueue’s Kevent, and Windows’s ReadDirectoryChangesW bindings). Everything else — event dispatch, the Op bitmask, buffer management — is standard library only (os, path/filepath, sync, errors). There is no build system beyond go build/go test; CI (.github/workflows/test.yml and staticcheck.yml) runs the test suite and staticcheck linting across the supported platforms rather than relying on any bundled task runner.
Code Quality
Each backend ships its own dedicated test file (backend_inotify_test.go, backend_kqueue_test.go, backend_windows_test.go, backend_fen_test.go) alongside shared cross-platform tests in fsnotify_test.go, helpers_test.go, and a synctest_test.go that exercises timing-sensitive event ordering. Error handling favors typed sentinel errors (ErrNonExistentWatch, ErrClosed, ErrEventOverflow) returned explicitly rather than panics or swallowed failures, and public functions/types carry substantial godoc comments explaining platform edge cases inline. A staticcheck.conf plus a dedicated CI lint workflow enforce static analysis on every push, and naming is consistently idiomatic Go (exported Watcher/Event/Op, unexported watchFlag, koekje cookie helper).
API Design
The public surface is deliberately minimal: construct a Watcher, call Add(path), and range over two channels — there’s no configuration object to assemble and no callback registration boilerplate. Op is a bitmask with a Has() helper so callers avoid brittle equality checks against multi-flag events, and the one platform-specific knob (WithBufferSize for Windows) is opt-in via a functional-options pattern (AddWith) rather than cluttering the common path. The tradeoff for this simplicity is that callers must implement their own recursion and debouncing, which the README states explicitly rather than leaving undocumented — the FAQ and platform-notes sections in the docs preempt the most common integration mistakes (watching individual files, NFS/FUSE limitations, Chmod noise).
Used by 24 apps in this directory
Gitea
Developer Tools · Devops · Project Management
Self-hosted DevOps in a single Go binary — Git hosting, GitHub Actions-compatible CI/CD, and 30+ package registries without any SaaS dependency.
Glasskube
Developer Tools · Devops
A next-generation Kubernetes package manager with a GUI, CLI, and native GitOps integration that makes deploying cluster workloads 20x faster than Helm.
Grafana
Analytics · Monitoring
The open-source observability platform that unifies metrics, logs, and traces from any data source into dynamic, queryable dashboards.
Hatchet
AI Development · Automation · Developer Tools
A Postgres-backed orchestration engine for background tasks, AI agents, and durable workflows that replaces Redis queues and multi-datastore durable execution platforms with a single self-hostable service.
NetBird
Security
Replace your VPN with a zero-trust WireGuard overlay network that auto-connects devices, enforces SSO and posture checks, and deploys in under 5 minutes.
Netdata
Devops · Monitoring
Real-time per-second metrics, ML-powered anomaly detection, and zero-config observability for any infrastructure.
Okteto
Developer Tools · Devops
Develop applications directly inside your Kubernetes cluster with real-time file sync and instant hot-reload — no more docker build/redeploy cycles.
Ory Kratos
Authentication
API-first identity and user management that handles login, registration, MFA, and recovery so your application never has to.
PocketBase
Authentication · Databases · Ecommerce
Open Source realtime backend in 1 file — embedded SQLite, auth, file storage, and admin UI as a single Go binary.