yosymfony/resource-watcher
A PHP library for watching files and directories for changes. It detects file creations, modifications, and deletions using inotify, polling, or hashing strategies, with a simple event-based API for building file monitors, hot-reload tools, and build watchers.
Build vs. buy for internal tooling. This is a "buy" (adopt) candidate for any non-differentiating capability that needs to react to file changes — hot reload, asset regeneration, cache invalidation, log tailing, config reloading. The core loop (poll a set of paths on an interval, hash each resource, diff against a persisted cache, emit created/modified/deleted) is exactly the kind of plumbing that looks trivial in a ticket and becomes a 2–3 week tail of edge cases in reality: debouncing, atomic writes, renamed files, deleted-then-recreated paths, symlinks, permission errors on partial reads. Adopting a library converts that tail into an integration task.
Feature scoping: file-change reaction as an enabler, not a product. If the roadmap item is "auto-recompile theme assets in the admin preview" or "reload worker config without a deploy," the file-watching mechanism itself is invisible to the customer. That argues strongly for the thinnest viable dependency rather than a bespoke subsystem the team then owns forever. This package's scope — polling plus checksums plus events — is narrowly matched to that need and does not drag in a daemon, a supervisor, or an inotify extension requirement.
Roadmap sequencing and risk. The library is MIT-licensed, has no paid tier, no vendor lock-in, and no runtime service dependency — it is a Composer package. That makes it cheap to try and cheap to abandon: a spike can validate the product behavior in days, and ripping it out later is a contained refactor behind an interface. This is the shape of dependency you want under an uncertain roadmap item, and it lets you commit to a demo date before committing to an architecture.
Use cases worth putting in front of the team:
config/, translation files, or a feature-flag file and flush the relevant cache store on change, instead of a cron that flushes blindly.Explicitly not supported as a decision: real-time guarantees. Because detection is polling plus checksum comparison rather than filesystem notifications, the product cannot honestly promise sub-second reaction or low CPU cost on large trees. If a roadmap item's success criteria include latency or footprint numbers, this package is the wrong lever and the decision should be scoped as "acceptable staleness, tuned by interval."
Dependency-footprint decision. It leans on Symfony Finder and Symfony EventDispatcher — components Laravel already ships or commonly carries. That means near-zero marginal install weight and a callback model (EventDispatcher) that Laravel engineers will read instantly, which lowers review friction and the cost of the code review that gates the merge.
Adopt when most of the following hold:
Finder constraints and EventDispatcher listeners, and you want the watched set defined declaratively ("everything under resources/views except *.swp") rather than hardcoded.Look elsewhere when:
inotify (Linux), FSEvents (macOS), or Watchman/Chokidar behind the same interface. Polling will not get you there, and no amount of interval tuning fixes the architectural gap.php artisan serve-adjacent tooling, Vite/HMR, or queue workers with restart-on-deploy may already solve the underlying user need without a new dependency. Check that the product requirement isn't already met before adding a watcher.To executives: We can satisfy a class of "the app should react when files change" requirements — hot reload, config and cache refresh, pipeline gating — by adopting a small MIT-licensed PHP library instead of building the mechanism ourselves. It is free, adds no service, no vendor relationship, and no infrastructure. The expected saving is a few weeks of engineering per use case, and the exit cost is low: it sits behind an interface, so if it stops being maintained we replace it in a contained piece of work rather than a rewrite. The tradeoff to accept knowingly is that reaction is interval-based, not instant — fine for developer and internal tooling, not fine for anything with a latency promise to a customer.
To engineering: Polling loop over Finder-filtered paths, checksums each resource, diffs against a persisted hash cache, and dispatches created/modified/deleted through Symfony's EventDispatcher — so your handlers are ordinary listeners and the watched set reads like a Finder query. It ships no daemon and needs no PHP extension. Two things to verify before we merge: current PHP and Laravel compatibility (last upstream release was 2020, low activity), and the polling cost on our largest watched tree. Plan to own the dependency — pin the version, isolate it behind our own watcher interface, and assume we fork rather than wait if a framework upgrade breaks it. For anything needing sub-second reaction or six-figure path counts, we go to inotify/FSEvents and keep the same interface.
How can I help you explore Laravel packages today?