For the complete documentation index, see llms.txt. This page is also available as Markdown.

Directory + File Watchers

Watch directories and react to file changes in real time

BoxLang ships with a runtime WatcherService that lets you watch directories and respond to filesystem activity with BoxLang listeners.

Watchers are useful for:

  • hot reload workflows

  • build and asset pipelines

  • ingest/ETL drop folders

  • automation on create, modify, and delete events

Event Model

Watchers emit events for:

Event
Trigger
Explanation

created

New file or directory exists

Fired when a new entry is added under a watched path.

modified

Existing entry changes

Fired when content or metadata updates are detected.

deleted

Existing entry is removed

Fired when an entry that previously existed is deleted.

overflow

Watch queue overflows

Indicates dropped events; re-sync state if needed.

A listener receives an event payload that includes event kind, watched root, path details, and timestamp.

Watcher Event Payload

Listeners receive a struct with these keys:

Key
Type
Description

kind

string

Event kind: created, modified, deleted, or overflow.

path

string

Absolute path for the affected entry; blank for overflow.

relativePath

string

Path relative to watchRoot; blank for overflow.

watchRoot

string

Registered watcher root; blank for overflow.

timestamp

string

ISO-8601 timestamp for when the event was emitted.

How Watchers Work

Watchers monitor filesystem changes and route events to your listener code. Here's how the flow works:

Event Processing Pipeline

Quick Start (Programmatic)

Watcher Listeners

BoxLang watchers support four listener patterns: closures, struct of closures, class name strings, and class instances. Choose the pattern that fits your complexity and reusability needs.

🔹 Closure Listener

The simplest approach—pass a closure that receives the event struct:

Best for: Quick prototypes, simple logging, and single-action handlers.

🔹 Struct of Closures

Map event kinds to specific handler closures for cleaner separation:

Best for: Event-specific logic without creating a full class, medium complexity handlers.

🔹 Class Listener

For production systems for full control and error handling. A class can maintain internal state, helper methods, and complex logic. It is mandatory to have a onEvent() method that receives the event struct.

The available methods are:

Method Name
Required
Description

onEvent()

Yes

Main event handler receiving all events. Must accept an event struct.

onCreate()

No

Called for created events. Receives event struct.

onModify()

No

Called for modified events. Receives event struct.

onDelete()

No

Called for deleted events. Receives event struct.

onOverflow()

No

Called for overflow events. Receives event struct.

onError()

No

Called when listener execution throws an exception.

When specific event methods (onCreate(), onModify(), onDelete(), onOverflow()) are defined, they are called in addition to onEvent(). Use onEvent() for centralized routing or implement specific methods for targeted handling.

Usage with class instance:

Usage with class name string:

Best for: Production systems, shared listener logic, complex error handling, testable code.

Global Startup Watchers

You can register auto-start watchers in boxlang.json:

See Watcher configuration for all options.

Application Watchers

If you want watchers to be app-scoped and auto-started from your Application.bx, define them in this.watchers.

See Application.bx Custom Watchers for full syntax, supported listener forms, and definition keys.

Watcher BIFs

BIF
Purpose

watcherNew()

Create and register a watcher

watcherStart()

Start a watcher

watcherStop()

Stop a watcher

watcherRestart()

Restart a watcher

watcherGet()

Retrieve one watcher

watcherGetAll()

Retrieve all watchers

watcherList()

List watcher names

watcherExists()

Check if watcher exists

watcherShutdown()

Stop and unregister one watcher

watcherStopAll()

Stop all watchers without unregistering

watcherShutdownAll()

Stop and unregister all watchers

WatcherInstance API

watcherNew() and watcherGet() return a WatcherInstance object you can inspect and control directly.

  • start()WatcherInstance: Start this watcher.

  • stop( force )WatcherInstance: Stop this watcher (force defaults to false).

  • restart()WatcherInstance: Stop and start this watcher.

  • isRunning()boolean: True when watcher state is RUNNING.

  • isStopped()boolean: True when watcher state is STOPPED.

  • getState()State: Raw enum state (CREATED, RUNNING, STOPPED).

  • getStateAsString()string: String state value.

  • getName()Key: Watcher identifier.

  • getWatchPaths()array: Configured watch roots.

  • getListener()IWatcherListener: Listener instance.

  • getStats()struct: Snapshot of watcher configuration and runtime status.

getStats() Properties

The getStats() method returns a struct with the following keys:

Property
Type
Description

name

string

Watcher identifier

state

string

Current watcher state (CREATED, RUNNING, STOPPED)

paths

array

Array of watch root paths

recursive

boolean

Whether subdirectories are monitored

debounce

numeric

Debounce delay in milliseconds (0 = disabled)

throttle

numeric

Throttle limit in milliseconds (0 = disabled)

atomicWrites

boolean

Whether atomic write detection is enabled

errorThreshold

numeric

Maximum consecutive errors before watcher stops

consecutiveErrors

numeric

Current count of consecutive errors since last success

Example:

Best Practices

  • Use debounce to avoid duplicate triggers from editor save behavior.

  • Use throttle for noisy directories with heavy write bursts.

  • Keep listener logic fast; hand off heavy work to async executors.

  • Set errorThreshold to prevent infinite noisy failures.

  • Prefer class listeners for production systems and shared logic.

Watcher lifecycle and errors are logged through the runtime watcher logger. See logging configuration for logger tuning.

Last updated

Was this helpful?