A shared-nothing io_uring runtime for .NET.
One ring per reactor thread, one reactor per core. Each reactor owns its ring, its SO_REUSEPORT
listener, its connections and its clients outright, so nothing is shared and nothing is locked - a
request never leaves the core it arrived on, inbound and outbound alike. What makes that practical
in .NET is that you do not give up the platform's async model to get it: handlers are ordinary
async Task code, ring completions resume their continuations inline on the reactor thread, and
a per-reactor SynchronizationContext catches everything that would otherwise escape - timers,
HttpClient, Task.Run. You always wake up on your reactor, so connection, pool and handler state
stays single-threaded without a lock in sight.
ioxide hands you raw bytes and stays out of HTTP; when you want a framework on top,
ioxide.Kestrel swaps the transport under an existing ASP.NET Core app with your endpoints
unchanged.
Linux 6.1+ · .NET 10 / .NET 11 ·
0.4.153- experimental
Documentation - architecture, guides, and every example as runnable code side by side.
Every package shares one version and depends only on the runtime. Start with
ioxide - reactors, TCP/UDP transports, connections,
the ring-native client seam, and TLS termination (OpenSSL handshake over the ring, then kTLS, so
handlers keep writing plaintext) - then add exactly what you use.
Protocols. HTTP/2 and HTTP/3 each come twice: a bundled native, or the same surface in pure C#.
| Package | What it does |
|---|---|
ioxide.ngtcp2 |
QUIC. ngtcp2 + picotls as one bundled native; only system dependency is OpenSSL 3. |
ioxide.nghttp3 |
HTTP/3 + QPACK (nghttp3), bundled native. Rides any QUIC connection. |
ioxide.http3 |
HTTP/3 in pure C# - frames, QPACK, Huffman. Zero native code, drop-in for ioxide.nghttp3. |
ioxide.nghttp2 |
HTTP/2 (nghttp2), bundled native. h2c, or h2 over TLS via ALPN. |
ioxide.http2 |
HTTP/2 in pure C# - framing, HPACK, flow control. Zero native code, drop-in for ioxide.nghttp2. |
Clients. One pool per reactor, opened on the reactor thread, so every call rides the ring that accepted the request.
| Package | What it does |
|---|---|
ioxide.httpclient |
HTTP/1.1, HTTP/2 and HTTP/3 behind one API, protocol chosen per origin via Alt-Svc, with client-side TLS for https://. |
ioxide.pg |
Postgres. Connect, query and stream rows on the owning ring. |
ioxide.redis |
Redis. RESP2, pipelining, pub/sub. |
ioxide.file |
Static assets. Immutable snapshots, baked responses, positional ring reads. |
Serving.
| Package | What it does |
|---|---|
ioxide.Kestrel |
ASP.NET Core transport: UseIoxide() and Kestrel runs one ring per core, its request loop pinned to the reactor thread. |
Nothing here is pseudocode. Every pattern above exists as something you can run:
| What you get | |
|---|---|
| Documentation | The examples browser - TCP with and without kTLS, HTTP/2, QUIC, HTTP/3, every client, and all nine proxy combinations, side by side. |
| Playground | One project per workload, grouped by topic. Each Program.cs is a complete server - config, reactors, threads, handler - so you can copy the file out and run it. |
| Examples.AspNet | UseIoxide() measured against a stock Kestrel baseline. |