FlatSharp generates C# classes that index straight into a FlatBuffers buffer
Fast, idiomatic C# implementation of Flatbuffers
At a glance
- What is it?
- FlatSharp is Google's FlatBuffers format implemented in C#, where a build-time compiler turns an FBS schema into subclasses whose properties read and write directly in the buffer rather than copying objects out of it. The project bets on safety over unsafe code, and its own documentation warns you not to pick a serializer on benchmark numbers alone.
- Who is it for?
- Adopt FlatSharp if your C# service needs a binary format with zero-copy reads, you can commit to compiling an FBS schema at build time, and your deployment targets include AOT, Unity, Blazor or Mono, since avoiding unsafe code and IL generation is what keeps those scenarios working.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 118 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Generated subclasses whose properties index into the buffer
The Internals section explains how FlatSharp avoids copying, and it does so with one sentence: FlatSharp works by generating subclasses of your data contracts based on the schema that you define. When you attempt to deserialize a MonsterTable object, you actually get back a subclass of MonsterTable, which has properties defined in such a way as to index into the buffer, according to the deserialization mode specified, greedy, lazy, and everything between.
That is the difference from most binary formats in .NET. A typical serializer walks a graph of objects and writes them out; reading it back builds a new object graph, allocating as it goes. Here the buffer stays where it is and the object you hold is a view over it. The properties do the indexing when you read them, so accessing a field is a buffer read rather than a lookup of a value that was copied out.
The memory model underneath is what makes that practical. FlatSharp is Google's FlatBuffers serialization format implemented in C#, for C#, and it uses the latest and greatest from .NET in the form of Memory<T> and Span<T>. The README draws a consequence from this: FlatSharp's safe-code implementations are often faster than other implementations using unsafe code. The argument is not that bounds checking is free, but that the modern span-based approach lets a safe implementation skip the pin and unsafe pointer work that other libraries need, and end up ahead anyway.
FlatBuffers itself is described as a zero-copy binary serialization format intended for high-performance scenarios. So the format was already designed around this idea of reading fields in place, and FlatSharp is a .NET-native implementation of that idea rather than a port of an existing C# library's approach.
The four priorities listed are Usability, Safety and Speed, Compatibility with other C#-focused projects like Unity, Blazor and Xamarin, and Compatibility with AOT scenarios including dotnet and Mono. The last two are the ones that shape the implementation more than the first two.
The schema is a build input, not documentation
The workflow starts with an FBS schema, and the FlatSharp-specific parts of it are marked with an fs_ prefix on their attributes. A minimal schema looks like this:
// all FlatSharp FBS attributes start with the 'fs_' prefix.
attribute "fs_serializer";
namespace MyNamespace;
enum Color : ubyte { Red = 1, Green, Blue }
table Person (fs_serializer) {
id : int;
name : string;
parent : Person (deprecated);
children : [ Person ];
favorite_color : Color = Blue;
position : Location;
}
struct Location {
latitude : float;
longitude : float;
}Two things in that schema are worth reading closely. The table carries (fs_serializer), which is the attribute that makes the compiler emit a serializer for it. The struct Location is a value type with no attribute, and the samples list includes a dedicated Example13-ValueStructs project, so the distinction between a table and a struct carries through to the generated code.
The schema then becomes a build item rather than a runtime artefact:
<ItemGroup>
<FlatSharpSchema Include="YourSchema.fbs" />
</ItemGroup>The compiler package turns that into C# at build time. The README is explicit about the two packages: FlatSharp.Runtime is the runtime library and you always need it, and FlatSharp.Compiler is the build time compiler for generating C# from an FBS schema. The quick start also says to use the same version for both.
That is a real difference from the reflection-based serializers, where a type attribute or a convention is enough. Here the contract is declared in a language designed for it, the compiler generates against it, and the schema is also the thing other FlatBuffers implementations can consume. The README points newcomers at Google's FlatBuffer overview and the schema writing guide, which is a fair signal that this is a different workflow from adding an attribute to a class.
Serializing and parsing through a generated serializer
Writing is a three-step sequence, and the middle step is the one that matters for how you size your buffers.
Person person = new Person(...);
int maxBytesNeeded = Person.Serializer.GetMaxSize(person);
byte[] buffer = new byte[maxBytesNeeded];
int bytesWritten = Person.Serializer.Write(buffer, person);GetMaxSize is called before the write, so you allocate exactly once and know the buffer is large enough. The write then returns the number of bytes actually written, which is normally less than the maximum because the maximum accounts for the worst case, including the variable-length parts.
Reading back is a single call:
Person p = Person.Serializer.Parse(data);There is no separate buffer class or reader object in the basic path, which is the ergonomics the Usability priority is about. The serializer comes from the generated type as a static member, so the type of the data and the code that serialises it are the same thing.
The samples solution is the real tutorial, and its directory names map out the feature surface: Example00-Basics, Example01-DeserializationModes covering lazy, greedy and everything in between, Example02-Vectors for lists, Example03-IOOptions, Example04-gRPC, Example05-CopyConstructors, Example06-FBS Includes, Example07-SortedVectors, Example08-IndexedVectors, Example09-Unions, Example10-SharedStrings for string deduplication, Example11-StructVectors for fixed-length struct vectors, Example12-WriteThrough for updating buffers in place, Example13-ValueStructs, and Example14-UnsafeOptions. Fifteen projects, each isolating one capability, which is a more useful structure than a single large demo.
Two of those are worth singling out. Write-through means updating a buffer in place without re-serialising the whole thing, which is the feature that makes FlatSharp viable for a mutable document rather than only a message. Shared strings means deduplicating repeated strings, which matters for real payloads where the same string appears many times and which a naive FlatBuffers writer would repeat.
Safety comes from refusing unsafe code and runtime codegen
The Security section is the most distinctive part of the README, because it states a position rather than describing a feature list. Serializers are a common vector for security issues, and FlatSharp takes a specific approach.
The four rules are: no unsafe code, with all operations bounds-checked; no IL generation; use standard .NET libraries for reading and writing from memory; and depth tracking enabled for recursive schemas to prevent stack overflows. There is also periodic, manual fuzz testing using SharpFuzz and AFL++.
Each rule removes a class of problem. Unsafe code is where buffer overruns and type confusion live, so excluding it removes the whole category rather than auditing it. IL generation is where a deserialiser can be handed a payload that constructs an object graph nobody intended, so excluding it removes that too. Depth tracking handles the recursive schema case, where a self-referential table could otherwise drive the parser into unbounded recursion and crash the process.
The README is honest that this is not absolute. FlatSharp does use some techniques such as MemoryMarshal.Read on certain hot paths, but these usages are narrowly scoped and well tested. And the claim about safe code being fast is a relative one, stated against other implementations that use unsafe code.
The testing story behind those claims is described in the README's introduction: the project is extensively tested using Mutation Testing, Code Coverage, Oracle Testing, Fuzz Testing and other techniques to ensure the library doesn't regress. Oracle testing is the interesting one, since it means checking FlatSharp against another implementation rather than against itself, which is the only way a serializer's correctness claim can be checked independently. The project also says it has shipped to production at Microsoft, Unity3D and others, with the full status in ProjectStatus.md.
The benchmark warning is the most useful paragraph in the README
FlatSharp's performance section ends with a paragraph that any author could have written and almost none did. The README says serialization benchmarks are not reflective of real-world performance, because processes rarely do serialization-only workflows. In reality your serializer is going to be competing for L1 cache and other resources along with everything else in your program and everything else on the machine. So while the benchmarks show FlatSharp is faster by a wide margin, these benefits may not translate to any practical effect in your environment, depending completely on your own workflows and data structures.
It then gives the actual decision criteria: do you need lazy access, do you care about compact message size, is serialization on your hot path. And it ends with don't make your choice based on the results of a benchmark that shows best-case results for all serializers by virtue of that being the scenario tested.
The benchmark setup itself is narrow and worth knowing before you read the numbers. The benchmarks were run on .NET 8.0 with PGO enabled, using a C# approximation of Google's FlatBuffer benchmark, and four serialization frameworks are compared with default settings: FlatSharp 7.5.0, Protobuf.NET 3.2.30, Google's C# Flatbuffers 22.10.26, and Message Pack C# 2.5.140. The full results for each version of FlatSharp are in the benchmarks folder, and the benchmark data also covers many FlatSharp configurations, such as sorted vectors and shared strings.
Two things stand out. First, the benchmarked FlatSharp version is 7.5.0, while the most recent release listed is 7.9.0, so the published numbers are not for the current version. Second, the competitors are all general-purpose serializers and Google's own FlatBuffers implementation, which is the comparison you want to make if you are choosing between formats. Comparing FlatSharp to Google Flatbuffers is a comparison of two implementations of the same format, and comparing it to Protobuf.NET or MessagePack is a comparison of formats with different size and speed trade-offs, which is a different question from which library is faster.
Where FlatSharp is the wrong choice
Three limits, and the first is a workflow constraint that lands on day one.
The first is that you must write a schema and rebuild on every change. For a service whose internal messages mirror its C# types, that is a second description of the same thing to maintain, and the compiler becomes part of your build loop rather than a library call. Projects that want to serialise an existing object graph with attributes, or that want to serialise something whose shape is only known at runtime, have no path here. The dependency list also carries real weight: the runtime package is always needed, and the compiler package has to run on every developer's machine and in CI.
The second is that FlatBuffers is not the format you want in every situation. The benchmark list includes Protobuf.NET and Message Pack C#, and those formats have properties FlatBuffers does not: schema evolution rules that are widely understood, and in Protobuf's case a self-describing wire format that does not require both ends to share a schema at all. If you are integrating with a system that does not speak FlatBuffers, choosing FlatSharp for your own services buys you nothing at the boundary.
The third is the version and maturity gap. The most recent release listed is 7.9.0 from 2025-05-26, with 7.8.0 from 2024-11-14 and 7.7.0 from 2024-06-03 before it, and the last push to the repository was on 2026-06-27. The benchmarked version is 7.5.0, which predates all three of those releases. The repository is not archived and the project describes itself as mature with production use at Microsoft and Unity3D, and there is a ProjectStatus.md and a wiki with detailed documentation, so this is not an abandoned project. It is a project whose releases and whose public benchmark numbers are not the same version, and that is the kind of gap you should check before pinning.
The alternative approach is Google's own C# FlatBuffers implementation, which the README benchmarks against and which produces the same wire format, so the two are drop-in compatible at the format level. The difference in approach is that FlatSharp generates subclasses with properties that index into the buffer and refuses unsafe code and IL generation, while the upstream implementation is a more conventional library that works directly against generated accessors and takes different positions on IL. If your team already has FlatBuffers experience and the upstream library is sufficient, the reason to switch is the safety posture and the C#-idiomatic ergonomics, not the benchmark table.
Editorial conclusion
Adopt FlatSharp if your C# service needs a binary format with zero-copy reads, you can commit to compiling an FBS schema at build time, and your deployment targets include AOT, Unity, Blazor or Mono, since avoiding unsafe code and IL generation is what keeps those scenarios working. Do not adopt it if you need reflection-based serialisation of arbitrary .NET types, because the schema is a required input rather than an optional description, and do not adopt it on the strength of its benchmark table, because the README itself warns that serialization-only benchmarks do not reflect real workloads. Verify first that the runtime and compiler packages are on the same version, since the README requires that, that the deserialization mode you pick matches how your code reads the data, since greedy and lazy have different cost profiles, and that the licence position for your use is acceptable given the Apache-2.0 grant.
Frequently asked questions
What is FlatSharp and how is it different from other FlatBuffers implementations?
FlatSharp is Google's FlatBuffers serialization format implemented in C#, where a build-time compiler generates subclasses of your data contracts whose properties index directly into the buffer according to the deserialization mode. It uses Memory<T> and Span<T>, and the README says its safe-code implementations are often faster than other implementations that use unsafe code.
How do I install and use FlatSharp in a C# project?
Reference FlatSharp.Runtime and FlatSharp.Compiler from NuGet using the same version for both, define your schema in an FBS file with fs_ prefixed attributes, add it to the csproj with a FlatSharpSchema item, and then use the generated serializer: Person.Serializer.GetMaxSize, Write and Parse.
Does FlatSharp use unsafe code or generate IL?
No on both counts. The README lists no unsafe code with all operations bounds-checked, no IL generation, use of standard .NET libraries for memory access, and depth tracking for recursive schemas to prevent stack overflows. It does use MemoryMarshal.Read on certain hot paths, narrowly scoped and well tested.
Which deserialization modes does FlatSharp support?
Lazy, greedy and everything in between, with the properties of the generated class indexing into the buffer according to the selected mode. The samples solution includes a dedicated Example01-DeserializationModes project alongside separate projects for vectors, IO options, gRPC, sorted vectors, unions, shared strings and write-through.
What licence is FlatSharp released under?
The repository carries an Apache-2.0 licence. All FlatSharp packages are published on nuget.org, with FlatSharp.Runtime as the runtime library you always need and FlatSharp.Compiler as the build time compiler.
Should I choose FlatSharp based on its benchmark results?
The README advises against it, saying serialization benchmarks are not reflective of real-world performance because a serializer competes for cache with everything else in the program. It suggests deciding instead on whether you need lazy access, whether compact message size matters, and whether serialization is on your hot path.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jamescourtney-flatsharp)Was this useful?