onChange listens for operations your app performs, and watchExternal hands you a live feed of changes made by other processes. Both return cleanup functions so you can remove listeners precisely when they are no longer needed.
onChange(callback)
onChange registers a listener that fires whenever your application performs any write operation on this config target. The operations it covers are: create, save, patch, delete, reset, and import. It does not fire for changes made by external processes — use watchExternal for that.
The method is async and returns a Promise<() => void>. You must await it to get the unlisten function; the unlisten function itself is synchronous. Call it when you no longer need the listener.
onChange is useful for keeping derived UI state in sync — for example, marking a settings form as “saved” after a save or patch fires.
watchExternal(callback)
watchExternal registers an OS-level file-system watcher on the config file and calls your callback whenever an external process modifies it. The callback receives a ConfigChangeEvent whose operation field is always "external_change".
The method returns an async stop function. You must await it to cleanly unregister both the JS event listener and the Rust-side file watcher.
ConfigChangeEvent
BothonChange and watchExternal pass a ConfigChangeEvent to your callback:
targetId is derived from the combination of fileName, baseDir, provider kind, and path options. It lets you safely share a single global event bus and route events to the right handler when you have multiple Configurate instances.
Typical pattern: auto-reload on external change
A common use case is reloading the in-memory config automatically when an external editor modifies the file — for example, a developer tweaking settings during development, or a companion CLI tool writing a config update.ConfigChangeEvent, you can also inspect event.fileName or event.targetId before deciding whether to reload.
Cleaning up listeners
1
Store the cleanup function
Assign the return value of
onChange or watchExternal to a variable in the scope that owns the listener’s lifetime.2
Call cleanup on unmount or teardown
In a React component, call cleanup inside the
useEffect return. In a Svelte component, use onDestroy. In plain TypeScript, call them whenever the owning object is disposed.3
Await the watchExternal stop function
Unlike
onChange, the stop function returned by watchExternal is async. Always await it so the Rust-side watcher is properly unregistered before the component or window closes.