Introducing Asynchronous I/O in Neo4j using io_uring
Senior Staff Software Engineer, Neo4j
5 min read

The next release of Neo4j introduces a feature we have been developing for some time and are now making publicly available: asynchronous I/O support.
Why Asynchronous I/O Matters
Historically, Neo4j has relied on synchronous I/O throughout the system. This means that every read or write was a blocking operation: the executing thread had to wait for the operating system to complete the request before it could continue. While this model is simple and predictable, it can introduce significant waiting time, particularly in cloud environments where I/O latencies tend to be higher.

Asynchronous I/O addresses this limitation by allowing multiple requests to be issued concurrently while the program continues execution and is notified on completion. For workloads that perform large numbers of I/O operations and do not need to wait for each individual operation to complete, this approach can deliver substantial performance improvements.
What we’re releasing
While asynchronous I/O is still at an early stage within Neo4j, we are ready to share the first parts of this work. Even in its initial form, it has the potential to deliver meaningful performance improvements for certain type of workloads, particularly in cloud environments where storage latency and concurrency characteristics can make non-blocking I/O especially valuable.
In this first iteration, async I/O support was added to the background page evictor — which frees pages from the page cache when the cache becomes full — and to the checkpointer, which flushes all modified pages from memory to storage. This is only the beginning. Future versions may extend async I/O support to additional parts of the database, gradually expanding where Neo4j can take advantage of asynchronous storage operations.
Getting started with asynchronous I/O in Neo4j
In 2026.04, Neo4j takes an important step toward modernizing I/O handling by introducing asynchronous I/O using io_uring on Linux, which uses a combination of ringbuffers to manage the I/O requests.
In synchronous mode each I/O would block execution until it completed, limiting throughput and leaving available I/O bandwidth underutilized and threads blocked. With asynchronous I/O, Neo4j can now issue requests without waiting, allowing other work to continue and making better use of system resources enabling higher throughput.
This initial delivery enables the background page evictor and checkpointer to take advantage of async I/O when available and configured. While still in its early stages, these components demonstrate the potential of non-blocking execution to improve database performance, particularly in cloud and high-latency environments.
Prerequisites
Asynchronous I/O is not enabled by default and requires a few conditions to be met:
- Neo4j Enterprise Edition
- Linux operating system
- liburing library installed
- JDK 25 or later
To verify whether Neo4j can leverage the underlying asynchronous I/O capabilities, you can check the diagnostics in the debug logs. When the system is able to use the io_uring provider, you will see:
Native async IO provider: IOUring based async provider is available.
If any of the required conditions are not met, the log will instead show:
Native async IO provider: async IO provider is not available.
This provides a quick way to confirm whether asynchronous I/O is active and ready for use in your environment.
Configuration
To enable asynchronous I/O in Neo4j, set the following neo4j setting:
server.memory.pagecache.async=true
Once enabled and all prerequisites are met, the background page evictor and checkpointer will switch to async mode. In this mode, Neo4j can perform significantly more I/O concurrently, improving efficiency and throughput.
Even while operating asynchronously, configured checkpoint limits such as db.checkpoint.iops.limit or db.checkpoint.throughput.limit are still respected. This allows you to safely experiment with these settings and optimize them for your environment.
With these new asynchronous capabilities, it’s also a good opportunity to reconsider whether the page cache could benefit from Direct I/O using:
server.memory.pagecache.directio=true
Direct I/O may not be suitable for all workloads, but if your Neo4j page cache is large enough to cover the entire database store, now could be a good time to revisit this option and evaluate potential performance improvements.
Metrics
When asynchronous I/O is configured and active, all existing metrics continue to work as before. In addition, several new metrics have been introduced specifically to track the asynchronous I/O operations.

Summary
This release marks the beginning of a broader journey to bring asynchronous I/O deeper into Neo4j, unlocking improved concurrency, higher throughput, and greater efficiency for future versions.
It introduces a completely new way for Neo4j to handle I/O, representing a significant milestone in what the database is capable of. Beyond the components enabled today, this lays the foundation for expanding asynchronous I/O to additional parts of Neo4j in future releases, opening the door to even greater performance and scalability.
Introducing Asynchronous I/O in Neo4j using io_uring was originally published in Neo4j Developer Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.








