ioxide 0.0.12

There is a newer version of this package available.
See the version list below for details.
dotnet add package ioxide --version 0.0.12
                    
NuGet\Install-Package ioxide -Version 0.0.12
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ioxide" Version="0.0.12" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ioxide" Version="0.0.12" />
                    
Directory.Packages.props
<PackageReference Include="ioxide" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ioxide --version 0.0.12
                    
#r "nuget: ioxide, 0.0.12"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ioxide@0.0.12
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ioxide&version=0.0.12
                    
Install as a Cake Addin
#tool nuget:?package=ioxide&version=0.0.12
                    
Install as a Cake Tool

ioxide ioxide.pg ioxide.file ioxide.tls ioxide.redis

A shared-nothing io_uring runtime for .NET.

One ring per reactor thread - run one per core. HTTP, Postgres, and file I/O submit on that ring and resume inline on the same thread. No thread pool on the hot path. No native dependencies - raw syscalls, nothing else.

Linux 6.1+ · .NET 10 · status 0.0.5 - experimental

Documentation - architecture, guides, the full picture

Quick start

dotnet run -c Release --project Playground                     # GET / → ok

PLAYGROUND_MODE=pg   dotnet run -c Release --project Playground  # SELECT 42 over the ring
PLAYGROUND_MODE=file dotnet run -c Release --project Playground  # static files off the ring

How it works

var reactor = new Reactor(id, new ServerConfig { Port = 8080 });

// Clients opened here ride this reactor's ring.
reactor.OnStart = r => PgPool.Start(r, pgOptions);

reactor.Handle = async (r, conn) =>
{
    var pool = r.GetService<PgPool>();

    // Carry for bytes a read leaves behind - the head of a split request.
    var inflight = new byte[16 * 1024];
    int inflightTail = 0;

    while (true)
    {
        // io_uring recv - resumes inline on the reactor.
        var snapshot = await conn.ReadAsync();

        var rings = conn.GetSnapshotMemories(snapshot);
        if (rings.Length > 0)
        {
            ReadOnlySequence<byte> data;
            if (inflightTail == 0 && rings.Length == 1)
            {
                // Hot path: one ring, no carry - a single zero-copy segment.
                data = new ReadOnlySequence<byte>(rings[0].Memory);
            }
            else if (inflightTail == 0)
            {
                // Several rings, no carry - chain them, still zero-copy.
                data = rings.ToReadOnlySequence();
            }
            else
            {
                // Cold path: the carry goes first so a split request reads whole.
                var first = new RingSegment(inflight.AsMemory(0, inflightTail), 0);
                var last  = first;
                for (int i = 0; i < rings.Length; i++)
                    last = last.Append(rings[i].Memory, rings[i].BufferId);
                data = new ReadOnlySequence<byte>(first, 0, last, last.Memory.Length);
            }

            // Walk every complete request; stop at the first partial one.
            // TryParseRequest, Request, and SqlFor are YOUR code - ioxide
            // hands you raw bytes and stays out of HTTP.
            long consumed = 0;
            bool respond  = false;
            while (TryParseRequest(data.Slice(consumed), out Request request, out long length))
            {
                consumed += length;

                // io_uring send + recv to Postgres, on the same ring.
                var rows = await pool.QueryAsync(SqlFor(request.Path));

                // ioxide doesn't speak HTTP for you - you write the bytes.
                string body = $"db={rows.Value}";
                conn.Write(Encoding.ASCII.GetBytes(
                    $"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: {body.Length}\r\n\r\n{body}"));
                respond = true;
            }

            // Whatever wasn't consumed (a partial request, or everything when
            // nothing completed) moves to the front of the carry - only then
            // do the buffers go back to the ring.
            ReadOnlySequence<byte> rest = data.Slice(consumed);
            rest.CopyTo(inflight);
            inflightTail = (int)rest.Length;

            conn.ReturnBuffers(rings);

            if (respond) await conn.FlushAsync();   // io_uring send, once per batch
        }

        if (snapshot.IsClosed)
        {
            conn.DecRef();
            return;
        }

        conn.ResetRead();
    }
};

// One reactor per core.
new Thread(reactor.Run).Start();
Product Compatible and additional computed target framework versions.
.NET net11.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net11.0

    • No dependencies.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on ioxide:

Package Downloads
ioxide.pg

Postgres driver for the ioxide io_uring runtime: pooled ring-native connections per reactor, ring-native connect and handshake, inline completion resume.

ioxide.file

File serving for the ioxide io_uring runtime: immutable asset snapshots with baked responses, pooled positional ring reads, atomic reloads.

ioxide.tls

TLS for the ioxide io_uring runtime: OpenSSL handshake driven over the ring, then kernel TLS (kTLS) transmit offload - handlers keep writing plaintext through the same connection API. Requires Linux kTLS (tls module) and OpenSSL 3.

ioxide.redis

Redis client for the ioxide io_uring runtime: pooled ring-native connections per reactor, full RESP2 protocol, a generic command API plus typed helpers (strings, keys, hashes, lists, sets, sorted sets, pub/sub, transactions, scripting), and pipelining. Inline completion resume.

ioxide.Kestrel

ASP.NET Core Kestrel transport backed by the ioxide io_uring runtime: one reactor (ring) per core, SO_REUSEPORT load-balanced, with Kestrel's HTTP request loop pinned to the reactor thread. Drop-in via UseIoxide().

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.17 165 6/23/2026
0.0.16 100 6/21/2026
0.0.15 96 6/21/2026
0.0.14 101 6/21/2026
0.0.13 104 6/21/2026
0.0.12 155 6/21/2026
0.0.11 130 6/20/2026
0.0.10 100 6/20/2026
0.0.9 97 6/20/2026
0.0.8 121 6/19/2026
0.0.7 108 6/17/2026
0.0.6 158 6/15/2026
0.0.5 183 6/13/2026
0.0.4 142 6/12/2026
0.0.3 136 6/12/2026
0.0.2 141 6/11/2026
0.0.1 117 6/11/2026