FlatSpanBuffers 1.1.0

dotnet add package FlatSpanBuffers --version 1.1.0
                    
NuGet\Install-Package FlatSpanBuffers -Version 1.1.0
                    
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="FlatSpanBuffers" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FlatSpanBuffers" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="FlatSpanBuffers" />
                    
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 FlatSpanBuffers --version 1.1.0
                    
#r "nuget: FlatSpanBuffers, 1.1.0"
                    
#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 FlatSpanBuffers@1.1.0
                    
#: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=FlatSpanBuffers&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=FlatSpanBuffers&version=1.1.0
                    
Install as a Cake Tool

FlatSpanBuffers

A Modern C# Runtime for FlatBuffers

FlatSpanBuffers is a span-centric C# runtime and code generator for FlatBuffers. It minimizes heap allocations with Span<T>, struct, and ref struct. The API gives more control of memory allocations to the caller, enabling buffers that can be read or built entirely on the stack.

The API intentionally preserves the FlatBuffers "flavor" -- table builders, field accessors, and the Object API are nearly identical so the adoption of FlatSpanBuffers requires only minor changes.

There are two variants of the generated code: IFlatbufferObject and IFlatbufferSpanObject. IFlatbufferObject supports heap allocations and builders using the convinent BufferBuilding patterns. IFlatbufferSpanObject uses ref struct and accepts Span<T> arguments for more control over how memory is allocated.

For full FlatBuffers documentation (schema language, wire format, etc.) see the FlatBuffers Documentation and the FlatBuffers GitHub repository.


Key Changes from FlatBuffers

Area What Changed
Buffer types ByteBuffer is now a struct; ByteSpanBuffer is a new ref struct wrapping Span<byte> for stack-allocated buffers.
Builders FlatBufferBuilder (array-backed) and FlatSpanBufferBuilder (ref struct, span-backed) share common logic through BufferBuilder.
Generics allows ref struct constraints (requires .NET 9+) let a single generic function serve both regular and ref struct buffer types.
No unsafe code AllowUnsafeBlocks is not required. No ENABLE_SPAN_T / UNSAFE_BYTEBUFFER preprocessor defines.
Vectors Scalar vectors return ReadOnlySpan<T> / Span<T> directly. Table/struct vectors use lightweight wrapper structs.
Verification Verifier is a ref struct operating on span-backed data.
GetRoot<T> Generic TryGetRoot<T> and GetRootUnchecked<T> to read root tables with or without calling the Verifier.
Nullables RefStructNullable<T> provides .HasValue / .Value for optional ref struct fields since Nullable<T> cannot wrap a ref struct.
Memory-mapped files ByteSpanBuffer can wrap a Span<byte> derived from a MemoryMappedViewAccessor, enabling zero-copy reads of FlatBuffers data directly from memory-mapped files.
JSON Migrated from Newtonsoft.Json to System.Text.Json.
Object API Pack / UnPack Pack / UnPack pre-size collections and reuse objects to reduce allocations. IFlatBufferObjectT supports object pooling by providing a Reset function.
Target .NET 10.

Benchmarks

All benchmarks compare the original Google.FlatBuffers, with FlatSpanBuffers. The summarized results below compare the original against stackalloc'd, ref struct StackBuffer objects.

See Benchmarks.md for the complete results.

vs Google.FlatBuffers

Measured on AMD Ryzen 7 7800X3D, .NET 10.0.4.

Scenario JIT (.NET 10.0) NativeAOT 10.0
Decode ~3.7x ~1.8x
Encode ~2.2x ~2.6x
Decode (Object API) ~2.6x ~1.6x
Encode (Object API) ~1.8x ~1.9x
Verify ~2.7x ~3.2x

vs FlatSharp

FlatSharp is a popular .NET FlatBuffers library that uses pre-compiled serializers (source-generated code, AOT-friendly) with a different performance profile. FlatSharp adds custom attributes to the schema to support the source generated code.

Ported FlatSharp Benchmarks into this benchmark's project for comparison.

FlatSpanBuffers outperforms FlatSharp on decoding and sorted vector lookups. FlatSharp far outperforms the ObjectApi. FlatSharp's AOT encode performance is impressive.

Scenario JIT (.NET 10.0) NativeAOT 10.0
Lazy Decode ~3.2x faster ~1.7x faster
Greedy Decode ~5.4x faster ~2.6x faster
Greedy Decode (Object API) ~equal ~1.4x slower
Encode ~10% slower ~26% slower
Encode (Object API) ~55% slower ~73% slower
Sorted Int Lookup ~3.7x faster ~7.3x faster
Sorted String Lookup ~1.7x faster ~2.4x faster

Quick Start

1. Build the compiler

cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release \
      -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF \
      -DFLATBUFFERS_BUILD_FLATHASH=OFF .
make -j

2. Write a schema

namespace MyGame;

table Weapon {
  name: string;
  damage: short;
}

table Monster {
  name: string;
  hp: short;
  weapons: [Weapon];
}

root_type Monster;

3. Generate C# code

./flatspan --csharp-spanbufs --gen-object-api monster.fbs

4. Build with FlatBufferBuilder

using FlatSpanBuffers;
using MyGame;

var builder = new FlatBufferBuilder(1024);

var weaponOneName = builder.CreateString("Sword");
var weaponTwoName = builder.CreateString("Axe");

var sword = Weapon.CreateWeapon(builder, weaponOneName, 3);
var axe = Weapon.CreateWeapon(builder, weaponTwoName, 5);

Span<Offset<Weapon>> weaponOffsets = stackalloc Offset<Weapon>[2];
weaponOffsets[0] = sword;
weaponOffsets[1] = axe;
var weapons = Monster.CreateWeaponsVectorBlock(builder, weaponOffsets);

var name = builder.CreateString("Orc");

Monster.StartMonster(builder);
Monster.AddName(builder, name);
Monster.AddHp(builder, 300);
Monster.AddWeapons(builder, weapons);
var orc = Monster.EndMonster(builder);
Monster.FinishMonsterBuffer(builder, orc);

5. Build with FlatSpanBufferBuilder

using FlatSpanBuffers;
using MyGame.StackBuffer;

// ByteSpanBuffer and FlatSpanBufferBuilder do not dynamically resize,
// provide all required buffer space up front. Use the stack or the heap.
Span<byte> buffer = stackalloc byte[1024];
Span<int>  vtables = stackalloc int[64];
Span<int>  vtableOffsets = stackalloc int[64];
var buf = new ByteSpanBuffer(buffer);
var builder = new FlatSpanBufferBuilder(buf, vtables, vtableOffsets);

var weaponOneName = builder.CreateString("Sword");
var weaponTwoName = builder.CreateString("Axe");

var sword = Weapon.CreateWeapon(ref builder, weaponOneName, 3);
var axe = Weapon.CreateWeapon(ref builder, weaponTwoName, 5);

Span<Offset<Weapon>> weaponOffsets = stackalloc Offset<Weapon>[2];
weaponOffsets[0] = sword;
weaponOffsets[1] = axe;
var weapons = Monster.CreateWeaponsVector(ref builder, weaponOffsets);

var name = builder.CreateString("Orc");

Monster.StartMonster(ref builder);
Monster.AddName(ref builder, name);
Monster.AddHp(ref builder, 300);
Monster.AddWeapons(ref builder, weapons);
var orc = Monster.EndMonster(ref builder);
builder.Finish(orc.Value);

6. Read data

using MyGame;

var bb = new ByteBuffer(receivedBytes);
var monster = Monster.GetRootAsMonster(bb);

// Scalar vector
var inventory = monster.Inventory;
if (inventory.HasValue)
{
    ReadOnlySpan<byte> items = inventory.Value;
    for (int i = 0; i < items.Length; i++)
        Console.WriteLine($"  item[{i}] = {items[i]}");
}

// Table vector
var weapons = monster.Weapons;
if (weapons.HasValue)
{
    var weaponsVec = weapons.Value;
    for (int i = 0; i < weaponsVec.Length; i++)
    {
        var w = weaponsVec[i];
        Console.WriteLine($"  {w.Name}: {w.Damage}");
    }
}

License

This project is derived from Google FlatBuffers and is licensed under the Apache License 2.0. See LICENSE for details.

Acknowledgments

FlatSpanBuffers is built on top of the FlatBuffers serialization library created by Google. The schema compiler, wire format, and much of the core C++ tooling originate from that project. The C# runtime and code generator were reworked by @bigjt-dev.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 30 3/14/2026
1.0.0 78 3/3/2026