Linux I/O methods for HTTP file serving: io_uring offers peak performance
This review analyzes vbernat's comparison of synchronous, epoll, and io_uring I/O methods for serving static files over HTTP. We examine their performance, complexity, and suitability for different…
This review analyzes vbernat's comparison of synchronous, epoll, and io_uring I/O methods for serving static files over HTTP. We examine their performance, complexity, and suitability for different web server architectures.
TL;DR
Best for: High-performance, low-latency static file serving on Linux where maximizing throughput is critical, io_uring is the clear winner. For applications needing a balance of performance and complexity, epoll remains a robust choice. Skip if: You require cross-platform compatibility without significant abstraction, or if your application's I/O demands are minimal, making the added complexity of io_uring unnecessary. Synchronous I/O is too slow for any serious web serving. Bottom line: io_uring delivers superior throughput for static file serving on modern Linux, but demands a higher development cost compared to epoll or synchronous approaches.
METHODOLOGY
This v0 review draws on the founder's published claims and code examples at https://theconsensus.dev/p/2026/05/18/serving-files-three-ways.html. Independent benchmarks are pending. We will re-test when claims diverge from observed behavior in future versions of this review.
This review covers the three distinct I/O methods — synchronous, epoll, and io_uring — as implemented and benchmarked by vbernat. The source signal provides C code implementations for each method, demonstrating how to serve a 100KB static file over HTTP. Benchmarking was performed using wrk on a small virtual machine, focusing on requests per second (RPS) and latency. The analysis primarily covers the technical details of each I/O model, their implementation complexity, and the observed performance characteristics on a Linux environment. The article was accessed on 2026-05-25.
What's not covered in this v0 review includes independent performance verification on different hardware or operating systems, long-term workflow integration, or an exhaustive analysis of edge cases such as very small or very large files, network congestion, or concurrent writes. Our assessment is based solely on the data and code provided by vbernat.
WHAT IT DOES
vbernat's article, "Serving files over HTTP three ways: synchronous, epoll, and io_uring," presents a direct comparison of three fundamental Linux I/O patterns for building a simple HTTP file server. Each method is implemented in C, showcasing the architectural differences and their impact on performance.
Synchronous I/O
The synchronous approach uses traditional blocking read() and write() calls. Each client connection is handled by a dedicated thread or process, blocking until I/O operations complete. This model is the simplest to implement, often serving as a baseline for understanding I/O performance. It is straightforward but inherently inefficient for high concurrency, as threads spend significant time waiting for I/O to finish, leading to high context switching overhead.
epoll for event-driven I/O
epoll is a Linux-specific API for non-blocking, event-driven I/O. It allows a single thread to monitor multiple file descriptors for readiness events (e.g., data available to read, socket ready to write). This model avoids the overhead of blocking calls and dedicated threads per connection, enabling higher concurrency and better resource utilization. The server polls for events, processes them, and then returns to polling, making it suitable for many modern high-performance network applications.
io_uring for kernel-level asynchronous I/O
io_uring is a newer Linux kernel interface, introduced in version 5.1, designed for truly asynchronous I/O. Unlike epoll, which signals when I/O can be performed, io_uring allows applications to submit I/O requests to the kernel and receive completion notifications later, without blocking. This minimizes context switches and system calls, as operations are handled entirely within the kernel. It is the most complex to implement but promises the highest performance for I/O-bound workloads by offloading much of the I/O management to the kernel.
WHAT'S INTERESTING / WHAT'S NOT
The most interesting aspect of vbernat's comparison is the clear performance hierarchy demonstrated across the three I/O methods. The article provides concrete numbers: synchronous achieves approximately 20,000 requests per second (RPS), epoll reaches around 100,000 RPS, and io_uring tops out at roughly 140,000 RPS. This 7x improvement from synchronous to io_uring is a compelling argument for investing in more complex I/O models when raw throughput is paramount. The article effectively illustrates the diminishing returns of scaling with threads (synchronous) versus event-driven (epoll) versus kernel-offloaded asynchronous (io_uring) I/O.
Another interesting point is the explicit inclusion of C code examples for each method. This transparency allows readers to inspect the implementation details and understand the complexity trade-offs directly. It moves beyond theoretical discussion to practical application, which is a hallmark of good engineering analysis. The focus on a common task, serving static files, makes the results immediately relatable to many web development scenarios.
What's less interesting, or rather, a known quantity, is the poor performance of synchronous I/O for web serving. While useful as a baseline, its limitations are well-understood in high-concurrency environments. The article confirms this, but it doesn't offer new insights into why it's slow beyond the fundamental blocking nature. The article's scope is also limited to Linux, which, while appropriate for discussing kernel-specific features like epoll and io_uring, means the findings are not directly transferable to other operating systems without significant re-evaluation. The lack of detailed hardware specifications for the
Pull quote: “io_uring delivers superior throughput for static file serving on modern Linux, but demands a higher development cost compared to epoll or synchronous approaches.”
Every claim ties to a primary source. See our methodology.