epoll vs inotify: What even is the difference?
Understanding epoll and inotify without the fluff.
I was watching a video on how Nginx works by ByteMonk, a beautifully crafted explanation of how Nginx manages to handle millions of requests using worker processes (not threads!). As explained in the video, unlike Apache’s thread-per-request model, Nginx typically spawns one process per core, each managing thousands of connections, all thanks to a Linux system call called epoll.
Naturally, I got curious. The way epoll was described sounded similar to inotify, and that led me to dig deeper. What even is epoll, and how does it help Nginx pull off this magic?
epoll
So, epoll is a Linux kernel interface that lets programs efficiently monitor multiple file descriptors (FDs) to know when I/O operations can be performed like reading from or writing to a socket without blocking. In traditional blocking I/O, a program would wait (or block) on one connection until it’s ready, which doesn’t scale well when you have thousands of connections. epoll solves this by allowing the program to register interest in certain events (like "data is ready to read") on many FDs and then wait for the kernel to notify it when those events occur. This means the program can manage thousands of connections from a single process without looping through each one or using a thread per connection.
In Nginx, epoll is used to keep track of many active network connections, specifically, their socket file descriptors (FDs). Every time a client connects to the server (like when you open a website), socket is created to communicate with that client. This socket is represented by a FD, and Nginx adds it to an internal list managed by epoll.
The worker process which is responsible for handling client requests calls a system function called epoll_wait(). This function tells the operating system: "Let me know when any of the sockets in my list are ready to read from or write to." The worker then pauses(blocks) and does nothing until the OS responds. It doesn't constantly check the sockets. Instead, it waits efficiently for a signal from the kernel.
As soon as one or more sockets have data to read (or are ready to be written to), the OS wakes up the worker process and tells it exactly which sockets are ready. Nginx can then quickly handle just those sockets without touching the others.
This design means Nginx doesn't need to create a thread or process for every connection. A single worker can handle thousands of connections at the same time, because it's not blocked by any one of them. It only works on sockets when there's actually something to do. That’s what makes Nginx incredibly fast and scalable under high traffic.
But Wait... What About inotify?
While epoll is a general purpose tool used to monitor any kind of file descriptor (like sockets or pipes), inotify is focused specifically on the file system. It's used when you want to get notified whenever something changes in the file system for example, when a file is modified, deleted, moved, or even opened or read.
This is extremely useful in development environments. Tools like nodemon, webpack, or vite use inotify under the hood to watch your source files. So when you save a file, inotify detects the change and triggers the necessary build or reload process.
There’s also a user-space tool called inotifywait. It’s a CLI wrapper around inotify that you can use to monitor file system events from a terminal. For example, running:
inotifywait -m ./srcwill continuously print events (like file modifications) happening in the ./src folder. This is super handy for scripting or debugging when building your own watch based tools.
To conclude(TLDR):
epoll: General purpose tool to monitor any FD (mostly used for network sockets in servers like Nginx).inotify: Filesystem specific tool used to track file level changes (great for hot reloading, backups, syncing, etc).
Also, fun fact: Nginx, like Node, is event-loop based, and that's where epoll's magic comes into play. However, there are a few key differences, which are also explained beautifully in ByteMonk’s explainer on how Nginx works:


Well written and explained!