# metawatch

> Recursive file and directory watcher for Node.js with debouncing, event deduplication, and zero dependencies.

Latest version **2.0.0** (published 2026-03-20) · MIT license · 0 weekly downloads

## Install

```sh
npm install metawatch
pnpm add metawatch
yarn add metawatch
bun add metawatch
```

## Health

**Score 65/100 (B)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.0.0 |
| Published | 2026-03-20 |
| First published | 2020-09-27 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=18 |
| Dependencies | 0 |
| Unpacked size | 11.6 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 14 |
| Author | Timur Shemsedinov |
| Maintainers | timur.shemsedinov |
| Keywords | fs, watch, file-watcher, directory-watcher, recursive, filesystem, inotify, debounce, metarhia |

## Links

- npm: https://www.npmjs.com/package/metawatch
- Repository: https://github.com/metarhia/metawatch
- Homepage: https://github.com/metarhia/metawatch#readme
- Issues: https://github.com/metarhia/metawatch/issues
- Funding: https://www.patreon.com/tshemsedinov
- npm.io page: https://npm.io/package/metawatch

## Alternatives

- [unionfs](https://npm.io/package/unionfs.md) — 2.2M weekly downloads
- [path-starts-with](https://npm.io/package/path-starts-with.md) — 35.9K weekly downloads
- [redzip](https://npm.io/package/redzip.md) — 1.2K weekly downloads
- [vscode-anymatch](https://npm.io/package/vscode-anymatch.md) — 848 weekly downloads
- [@ledgerhq/coin-filecoin](https://npm.io/package/@ledgerhq/coin-filecoin.md) — 793 weekly downloads

## Recent versions

- 2.0.0 (latest) — 2026-03-20
- 1.2.5 — 2026-03-18
- 1.2.4 — 2025-09-13
- 1.2.3 — 2025-05-25
- 1.2.2 — 2024-08-30
- 1.2.1 — 2023-12-11
- 1.2.0 — 2023-10-27
- 1.1.1 — 2023-06-04
- 1.1.0 — 2023-06-03
- 1.0.8 — 2023-04-29
- 1.0.7 — 2022-11-17
- 1.0.6 — 2022-07-07
- 1.0.5 — 2022-03-18
- 1.0.4 — 2021-07-17
- 1.0.3 — 2021-04-06
- … 4 more at https://npm.io/package/metawatch/versions

## README

# Metawatch

[![ci status](https://github.com/metarhia/metawatch/workflows/Testing%20CI/badge.svg)](https://github.com/metarhia/metawatch/actions?query=workflow%3A%22Testing+CI%22+branch%3Amaster)
[![snyk](https://snyk.io/test/github/metarhia/metawatch/badge.svg)](https://snyk.io/test/github/metarhia/metawatch)
[![npm version](https://badge.fury.io/js/metawatch.svg)](https://badge.fury.io/js/metawatch)
[![npm downloads/month](https://img.shields.io/npm/dm/metawatch.svg)](https://www.npmjs.com/package/metawatch)
[![npm downloads](https://img.shields.io/npm/dt/metawatch.svg)](https://www.npmjs.com/package/metawatch)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/metarhia/metawatch/blob/master/LICENSE)

Recursive file and directory watcher for Node.js with debouncing, event deduplication, and zero dependencies.

## Features

- 🔍 **Recursive directory watching**: auto and recursive watches subdirectories
- 🔄 **Dynamic directory management**: auto adds new directories and removes deleted ones
- ⚡ **Event deduplication**: prevents duplicate events for the same file changes
- 🎯 **Debounced events**: batches multiple changes within a configurable timeout
- 📦 **Zero dependencies**, uses only Node.js built-in modules
- 🎭 **EventEmitter API**: simple event-driven interface

## Installation

Requires Node.js 18 or later.

```bash
npm i metawatch
```

## Quick Start

```js
const metawatch = require('metawatch');

const watcher = new metawatch.DirectoryWatcher({ timeout: 200 });
watcher.watch('/path/to/directory');

watcher.on('change', (fileName) => {
  console.log('File changed:', fileName);
});

watcher.on('delete', (fileName) => {
  console.log('File deleted:', fileName);
});
```

## API Reference

### DirectoryWatcher

```js
new DirectoryWatcher(options);
```

**Options:**

- `timeout` (number, optional): Debounce timeout in milliseconds. Default: `5000`

**Methods:**

- `watch(targetPath)` - Start watching directory recursively
- `unwatch(targetPath)` - Stop watching directory
- `close()` - Stop all watchers, clear timers and internal state

**Events:**

- `change` - File created/modified (`filePath`)
- `delete` - File deleted (`filePath`)
- `before` - Before processing batch (`changes` array of `[filePath, eventName]` tuples)
- `after` - After processing batch (`changes`)

## Examples

### Basic File Watching

```js
const metawatch = require('metawatch');

const watcher = new metawatch.DirectoryWatcher({ timeout: 500 });

watcher.watch('./src');

watcher.on('change', (fileName) => {
  console.log(`File changed: ${fileName}`);
  // Trigger rebuild, reload, etc.
});

watcher.on('delete', (fileName) => {
  console.log(`File deleted: ${fileName}`);
  // Clean up references, etc.
});
```

### File System Backup Monitor

```js
const metawatch = require('metawatch');
const fs = require('node:fs');

const watcher = new metawatch.DirectoryWatcher({ timeout: 1000 });
const backupQueue = new Set();

watcher.watch('/important/documents');

watcher.on('change', (fileName) => {
  console.log(`File modified: ${fileName}`);
  backupQueue.add(fileName);
});

watcher.on('delete', (fileName) => {
  console.log(`File deleted: ${fileName}`);
  // Remove from backup if it exists
  backupQueue.delete(fileName);
});

watcher.on('after', (changes) => {
  if (backupQueue.size > 0) {
    console.log(`Backing up ${backupQueue.size} files...`);
    // Process backup queue
    backupQueue.clear();
  }
});
```

### Multiple Directory Monitoring

```js
const fs = require('node:fs');
const path = require('node:path');
const metawatch = require('metawatch');

const watcher = new metawatch.DirectoryWatcher({ timeout: 200 });

const directories = ['./src', './tests', './docs', './config'];

directories.forEach((dir) => {
  if (fs.existsSync(dir)) {
    watcher.watch(path.resolve(dir));
    console.log(`Watching: ${dir}`);
  }
});

watcher.on('change', (fileName) => {
  const relativePath = path.relative(process.cwd(), fileName);
  console.log(`Changed: ${relativePath}`);
});

watcher.on('before', (changes) => {
  console.log(`Processing ${changes.length} changes...`);
});

watcher.on('after', (changes) => {
  console.log(`Completed processing ${changes.length} changes`);
});
```

### TypeScript Usage

```ts
import { DirectoryWatcher, DirectoryWatcherOptions } from 'metawatch';

const options: DirectoryWatcherOptions = {
  timeout: 500,
};

const watcher = new DirectoryWatcher(options);

watcher.watch('./src');

watcher.on('change', (fileName: string) => {
  console.log(`File changed: ${fileName}`);
});

watcher.on('delete', (fileName: string) => {
  console.log(`File deleted: ${fileName}`);
});
```

## Error Handling

```js
const watcher = new metawatch.DirectoryWatcher();

watcher.on('error', (error) => {
  console.error('Watcher error:', error);
});

try {
  watcher.watch('/restricted/path');
} catch (error) {
  console.error('Failed to watch directory:', error.message);
}
```

## Contributors

See [AUTHORS](./AUTHORS) and [contributors on GitHub](https://github.com/metarhia/metawatch/graphs/contributors).

## License & Contributors

Copyright (c) 2020-2026 [Metarhia contributors](https://github.com/metarhia/metawatch/graphs/contributors).
Metawatch is [MIT licensed](./LICENSE).
Metawatch is a part of [Metarhia](https://github.com/metarhia) technology stack.

---
_Source: https://npm.io/package/metawatch · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
