Last modified: April 27, 2026
This article is written in: πΊπΈ
Inotify is a Linux kernel subsystem that provides a mechanism for monitoring file system events. It allows applications to watch files and directories for changes such as creation, deletion, modification, and access. Rather than repeatedly polling the file system to detect changes, inotify delivers event notifications directly to user-space programs, making it both efficient and responsive.
System administrators, developers, and DevOps engineers rely on inotify for tasks ranging from live log monitoring and automated backup triggers to build-system watchers and security auditing. The kernel-level integration means inotify imposes minimal overhead, even when watching large numbers of files.
| Inotify Workflow Overview |
+------------------------------------------------------------------+
β
βΌ
+--------------------------------------+ +----------------------------------+
| User-Space Application | | Kernel (VFS Layer) |
| (Creates inotify instance and | | (Tracks watched inodes and |
| adds watches on files/dirs) | | generates events on changes) |
+--------------------------------------+ +----------------------------------+
β β
β inotify_init() / inotify_add_watch() β
--------------------------------------------------------
|
βΌ
+-------------------------------+
| Inotify File Descriptor |
| (Readable via read()/poll() |
| when events are queued) |
+-------------------------------+
β
β Kernel queues inotify_event
β structs as changes happen
βΌ
+---------------------------------+
| Application Reads Events |
| (Processes each event and acts) |
+---------------------------------+
inotify_init() to create an inotify instance, which returns a file descriptor used for all subsequent operations.inotify_add_watch(), specifying a path and a bitmask of event types to monitor (e.g., IN_MODIFY, IN_CREATE, IN_DELETE).inotify_event structure on the inotify file descriptor's read queue.read() on the file descriptor, or uses poll()/select()/epoll() to wait for events without busy-looping.inotify_rm_watch(), and closing the inotify file descriptor cleans up all associated watches automatically.Inotify can watch for a variety of file system events. The table below lists the most commonly used event masks.
| Event Mask | Description |
IN_ACCESS |
File was accessed (read). |
IN_MODIFY |
File was modified (write). |
IN_ATTRIB |
Metadata changed (permissions, timestamps, extended attributes). |
IN_CLOSE_WRITE |
File opened for writing was closed. |
IN_CLOSE_NOWRITE |
File opened read-only was closed. |
IN_OPEN |
File was opened. |
IN_MOVED_FROM |
File was moved out of the watched directory. |
IN_MOVED_TO |
File was moved into the watched directory. |
IN_CREATE |
File or directory was created in the watched directory. |
IN_DELETE |
File or directory was deleted from the watched directory. |
IN_DELETE_SELF |
Watched file or directory itself was deleted. |
IN_MOVE_SELF |
Watched file or directory itself was moved. |
Convenience masks combine related events for common use cases:
| Convenience Mask | Equivalent Events | |
IN_CLOSE |
IN_CLOSE_WRITE \ |
IN_CLOSE_NOWRITE |
IN_MOVE |
IN_MOVED_FROM \ |
IN_MOVED_TO |
IN_ALL_EVENTS |
All of the above events combined. |
The inotify-tools package provides two command-line utilities that expose the inotify API without writing any code.
On Debian/Ubuntu-based systems:
sudo apt install inotify-tools
On Red Hat/Fedora-based systems:
sudo dnf install inotify-tools
On Arch Linux:
sudo pacman -S inotify-tools
inotifywait blocks until one or more inotify events occur on the specified files or directories. It is the most commonly used tool for scripting file-system triggers.
I. Watch a single file for modification:
inotifywait -e modify /var/log/syslog
When /var/log/syslog is written to, the command prints the event and exits:
/var/log/syslog MODIFY
II. Continuously monitor a directory for any changes:
inotifywait -m -r /home/user/projects
The -m flag keeps the watcher running (monitor mode) and -r watches all subdirectories recursively. Sample output as files change:
/home/user/projects/ CREATE main.c
/home/user/projects/ MODIFY main.c
/home/user/projects/ CLOSE_WRITE,CLOSE main.c
/home/user/projects/build/ CREATE output.o
III. Watch for specific events with a custom output format:
inotifywait -m -r -e create -e delete --format '%T %w%f %e' --timefmt '%Y-%m-%d %H:%M:%S' /etc
This monitors /etc for file creation and deletion, printing a timestamped log:
2025-03-21 10:15:42 /etc/nginx/sites-enabled/mysite CREATE
2025-03-21 10:16:03 /etc/nginx/sites-enabled/oldsite DELETE
inotifywatch collects file system event statistics over a period of time, rather than printing individual events. This is useful for profiling which files or directories see the most activity.
I. Gather statistics for 60 seconds on a directory:
inotifywatch -t 60 -r /var/log
After 60 seconds, it prints a summary table:
total access modify close_write open filename
45 12 8 8 17 /var/log/
22 5 6 6 5 /var/log/nginx/
9 3 2 2 2 /var/log/auth.log
II. Focus on specific event types:
inotifywatch -t 30 -e modify -e create /home/user/uploads
Inotify is especially powerful when combined with shell scripts to automate responses to file system changes.
This script watches a directory and copies any modified or newly created file to a backup location:
#!/bin/bash
WATCH_DIR="/home/user/documents"
BACKUP_DIR="/home/user/backups"
inotifywait -m -r -e close_write -e moved_to --format '%w%f' "$WATCH_DIR" |
while read -r FILE; do
RELATIVE="${FILE#$WATCH_DIR/}"
mkdir -p "$BACKUP_DIR/$(dirname "$RELATIVE")"
cp "$FILE" "$BACKUP_DIR/$RELATIVE"
echo "Backed up: $RELATIVE"
done
close_write to trigger only after a file has been completely written and closed.moved_to event catches files moved into the directory.--format '%w%f' outputs the full path of the affected file for easy processing.This script monitors a log file for error messages and sends a notification:
#!/bin/bash
LOG_FILE="/var/log/application.log"
inotifywait -m -e modify --format '%w%f' "$LOG_FILE" |
while read -r FILE; do
if tail -n 1 "$FILE" | grep -qi "error"; then
echo "ERROR detected in $FILE at $(date)" >> /var/log/alert.log
fi
done
For applications that need tighter integration, the inotify system calls are available directly in C.
| inotify C API Flow |
+------------------------------------------+
| |
| 1. fd = inotify_init() |
| β |
| βΌ |
| 2. wd = inotify_add_watch(fd, |
| "/path", IN_MODIFY | IN_CREATE)|
| β |
| βΌ |
| 3. read(fd, buf, BUF_LEN) |
| β |
| βΌ |
| 4. Process inotify_event structs |
| from buf |
| β |
| βΌ |
| 5. inotify_rm_watch(fd, wd) |
| close(fd) |
+------------------------------------------+
A minimal C program that watches a directory:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/inotify.h>
#define BUF_LEN (10 * (sizeof(struct inotify_event) + 256))
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <path>\n", argv[0]);
exit(EXIT_FAILURE);
}
int fd = inotify_init();
if (fd == -1) {
perror("inotify_init");
exit(EXIT_FAILURE);
}
int wd = inotify_add_watch(fd, argv[1], IN_CREATE | IN_DELETE | IN_MODIFY);
if (wd == -1) {
perror("inotify_add_watch");
exit(EXIT_FAILURE);
}
printf("Watching %s for changes...\n", argv[1]);
char buf[BUF_LEN];
for (;;) {
ssize_t len = read(fd, buf, BUF_LEN);
if (len <= 0) {
perror("read");
exit(EXIT_FAILURE);
}
char *ptr = buf;
while (ptr < buf + len) {
struct inotify_event *event = (struct inotify_event *)ptr;
if (event->mask & IN_CREATE) printf("CREATED: %s\n", event->name);
if (event->mask & IN_DELETE) printf("DELETED: %s\n", event->name);
if (event->mask & IN_MODIFY) printf("MODIFIED: %s\n", event->name);
ptr += sizeof(struct inotify_event) + event->len;
}
}
inotify_rm_watch(fd, wd);
close(fd);
return 0;
}
Inotify operates within kernel-imposed limits that control resource usage. These limits can be viewed and adjusted through /proc/sys/fs/inotify/.
| Parameter | Description | Default |
max_user_instances |
Maximum number of inotify instances per user. | 128 |
max_user_watches |
Maximum number of watches per user across all instances. | 65536 |
max_queued_events |
Maximum number of events queued before events start being dropped. | 16384 |
I. View the current watch limit:
cat /proc/sys/fs/inotify/max_user_watches
II. Temporarily increase the watch limit:
sudo sysctl fs.inotify.max_user_watches=524288
III. Make the change persistent across reboots by adding to /etc/sysctl.conf:
echo "fs.inotify.max_user_watches=524288" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Applications that monitor many files (such as IDEs, build tools, or file-syncing utilities) may require increasing max_user_watches. The kernel allocates approximately 1 KB of kernel memory per watch on 64-bit systems, so setting the limit to 524288 uses roughly 512 MB of memory.
| Feature | Inotify | fanotify | dnotify (legacy) |
| Granularity | File and directory level | Filesystem-wide or mount-point | Directory level only |
| Recursive watching | Not built-in (requires manual) | Mark entire mount points | Not supported |
| Permission decisions | No | Yes (allow/deny file access) | No |
| Event detail | Rich (path, mask, cookie) | Rich (includes file descriptor) | Signal-based, limited info |
| Kernel version required | 2.6.13+ | 2.6.37+ | 2.4+ |
| Typical use case | File watchers, build tools | Antivirus, access control | Legacy applications |
inotifywait, Node.js fs.watch, Python watchdog) are built on it.make, webpack, and cargo use inotify to detect source file changes and trigger automatic rebuilds.rsync-based watchers and lsyncd use inotify to detect changes and replicate them to remote servers in near real-time./etc/passwd, /etc/shadow) for unauthorized modifications.inotify-tools on your system and use inotifywait to monitor your home directory for any file creation events. Create a few files and observe the output.inotifywait in monitor mode to watch a directory and log every modification event with a timestamp to a log file.inotifywatch to gather file system event statistics on /tmp for two minutes, then analyze which event types occurred most frequently./proc/sys/fs/inotify/. Explain what each parameter controls and when you might need to increase them..tmp extension to a designated cleanup folder./etc for any changes using inotifywait with recursive mode. Make a small configuration change and verify that inotify reports it correctly.inotifywait when watching a single file versus a directory. Explain the differences in event reporting and the role of the filename field in inotify_event.inotifywait monitor on a directory, and in the other, perform operations such as creating, renaming, and deleting files. Observe how rename events use the cookie field to pair IN_MOVED_FROM and IN_MOVED_TO.