ioxide knowledge base
The shared-nothing io_uring runtime for .NET
One ring per reactor thread, completions that resume your code inline on that thread, and protocol stacks and clients built on the same loop. How it works, and how to use it.
One ring per reactor
Each core runs a reactor: an io_uring ring and a thread that accept their own connections.
Inline completions
Receives, sends, connects, timers and file reads complete on that thread, and an await resumes right there.
Nothing shared
No thread pool in the path, and nothing between reactors to lock.
Protocols and clients
HTTP/2, HTTP/3 over QUIC, TLS and kTLS, and clients for HTTP, Postgres and Redis, all on the same loop.
What ioxide is#
An ioxide server runs one reactor per core. Each reactor owns an io_uring ring and a thread, accepts its own connections and never hands them to another thread: a request is read, handled and answered where it arrived. Work submitted to the ring - receives, sends, connects, timers, file reads - completes on that same thread, and an await on it resumes inline. There is no thread pool in the path and nothing shared between reactors to lock.
On top of the reactor sit the protocol stacks - HTTP/2 (pure C# and nghttp2) and HTTP/3 over QUIC (pure C# and nghttp3, with ngtcp2) - TLS (BoringSSL, bundled, with kernel TLS offload), and clients that use the same ring: HTTP/1.1, Postgres, Redis, files and timers. A client opened on a reactor belongs to it, so a handler that calls an upstream never leaves its thread on the way out or back.
Topics#
Runtime#
Core runtime
Reactors, the ring, inline completions, the reactor's synchronization context, tickers and services.
TCP connections
Handlers, the receive queue, writes and flushes, pipes, timeouts, and the reference that keeps a connection alive.
TLS and kTLS
BoringSSL over the ring, kernel TLS offload, certificates, several names on one port, rotation and mutual TLS.
Protocols#
HTTP/2
The pure C# stack and nghttp2: buffered and streamed handlers, flow control, h2 and h2c.
HTTP/3 and QUIC
ngtcp2 on the ring, connections across reactors, migration, the two HTTP/3 layers and raw QUIC.
Clients#
HTTP client
A warm pool for one long-lived upstream - the reverse-proxy shape - and RingHttpClient for any URL, with DNS, IPv6, TLS and redirects.
Postgres and Redis
A ring-native Postgres pool per reactor, and StackExchange.Redis with its connections on the ring.
Files and timers
File reads on the ring, static files served from disk, and deadlines kept by the ring itself.
Start here#
New to ioxide? Read the core runtime first - reactors, the ring and why nothing leaves its thread - then TCP connections, which every server is built from. Add TLS, then the protocol you serve and the clients you call. How the HTTP client works shows one reactor's pool in 3D.
The pages document ioxide 0.18.374. Since that release, TLS - on the server, in the HTTP client and in QUIC - runs on a BoringSSL that ships in the packages; 0.17.340 and earlier used the system's OpenSSL 3.