Open-source project
Cysharp/MemoryPack avatar
Cysharp/MemoryPack

MemoryPack: a zero-encoding binary serializer for C# and Unity

Zero encoding extreme performance binary serializer for C# and Unity.

4,742 stars316 forksC#MIT

At a glance

What is it?
MemoryPack trades schema portability for raw copy speed by generating C#-specific formatters at compile time. Here is how the source generator works, how to install it, and where the approach stops being the right choice.
Who is it for?
Adopt MemoryPack when both ends of the wire are C# and you control the schema, especially for struct arrays where the README claims the largest gains over other binary serializers. Do not adopt it when a non-C# service must read the payload, when you need a published wire format, or when your serialized types change often and you cannot coordinate both sides.
Can I use it commercially?
Yes. MIT 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 1 day 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 September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem MemoryPack solves, and who actually has it

Most binary serializers spend time on encoding work: writing variable-length integers, tags, and length prefixes for every field. MemoryPack's README describes its format as a zero-encoding design that copies as much C# memory as possible, and compares the approach to FlatBuffers while noting that MemoryPack's serialization target is a plain POCO rather than a special generated type. That is the pitch: keep ordinary C# classes, skip the per-field encoding overhead.

The audience is narrow and specific. If both the writer and the reader are C# (or Unity), and you control both ends, the format does not need to be readable by anything else. That is where the design pays off. The README positions the library against System.Text.Json, protobuf-net, MessagePack for C#, and Orleans.Serialization, and states that for standard objects MemoryPack is roughly ten times faster, and for struct arrays up to fifty to two hundred times faster. Those figures come from the project's own comparison on a .NET 7 / Ryzen 9 5950X machine, so treat them as the author's measurement, not an independent one. The author also notes this is his fourth serializer, after ZeroFormatter, Utf8Json, and MessagePack for C#, which is useful context: the design choices here are deliberate corrections to earlier attempts, not a first draft.

How the source generator turns a partial class into a formatter

MemoryPack does not reflect over your types at runtime. Annotating a class with [MemoryPackable] and the partial keyword causes an incremental source generator to emit an implementation of IMemoryPackable<T> for that type. The README points out that you can inspect the result in Visual Studio with Ctrl+K, R on the class name and then selecting the *.MemoryPackFormatter.g.cs file. That generated code is what actually runs.

The consequence is that the serialization contract is fixed at compile time. There is no IL.Emit and no dynamic code generation, which the README lists as a feature and which matters for Native AOT, where runtime code generation is not available. It also means a type that is not partial, or a build environment whose Roslyn is too old to run the generator, fails at build time rather than at first serialization.

What gets serialized depends on the type. For a struct or record struct containing no reference types, the README states that no additional annotation is used and the value is serialized directly from memory. For everything else, public instance properties and fields are serialized by default, with [MemoryPackIgnore] to exclude a member and [MemoryPackInclude] to promote a private one. That default is worth pausing on: adding a new public property to a serialized class silently changes the wire format unless you exclude it.

Installing MemoryPack and serializing a first object

The library ships on NuGet. The README gives the package-manager command and states that the minimum requirement is .NET Standard 2.1, with .NET 7 recommended for best performance. It also states that the code editor needs Roslyn 4.3.1 support, naming Visual Studio 2022 version 17.3 and .NET SDK 6.0.401 as examples, and links to Microsoft's Roslyn version support document for the details. Unity is a separate installation path; the README directs you to its Unity section rather than reusing these steps.

bash
Install-Package MemoryPack

With the package restored, define a serializable type. The README's example is a partial class with the attribute applied:

csharp
using MemoryPack;

[MemoryPackable]
public partial class Person
{
    public int Age { get; set; }
    public string Name { get; set; }
}

After saving, the generator emits the formatter. Serialize and deserialize through the static serializer:

csharp
var v = new Person { Age = 40, Name = "John" };

var bin = MemoryPackSerializer.Serialize(v);
var val = MemoryPackSerializer.Deserialize<Person>(bin);

The README states that Serialize can return byte[] or write to an IBufferWriter<byte> or a Stream, and that Deserialize accepts ReadOnlySpan<byte>, ReadOnlySequence<byte>, or a Stream, with non-generic overloads also available. If the build fails instead of producing a formatter, the two things to check first are the partial keyword and the Roslyn version.

What the built-in type list covers, and what it quietly assumes

The README enumerates a long set of types that serialize without custom formatters: .NET primitives, unmanaged types including any enum and any struct without reference types, string, decimal, Half, Int128, UInt128, Guid, Rune, BigInteger, the date and time types, the System.Numerics and Unity math types, Uri, Version, StringBuilder, Type, BitArray, CultureInfo, arrays up to four dimensions, Memory<>, ReadOnlyMemory<>, ArraySegment<>, ReadOnlySequence<>, Nullable<>, Lazy<>, KeyValuePair<,>, Tuple<,...>, ValueTuple<,...>, the common generic collections, the concurrent collections, and the immutable collections and their interfaces.

That breadth is the practical reason to consider MemoryPack over writing your own formatter layer. The gaps are more interesting than the list. CultureInfo and Type are both supported, which means the serializer has to encode something beyond raw memory for those cases; the zero-encoding claim applies to the fast path, not uniformly. And the list says nothing about how a Type is resolved on the reading side, which is the kind of detail you would want to confirm before putting it in a persisted format. For most applications the safe subset is primitives, strings, and collections of your own [MemoryPackable] types.

The trade-offs: schema coupling, version tolerance, and Unity

The strongest argument against MemoryPack in a given codebase is that its format is C#-specific by design. The README presents that as the source of the speed. It also means a Python, Go, or Rust service cannot read the payload, and there is no .proto or .fbs file to hand to another team. If your serialized data crosses a language boundary, protobuf or FlatBuffers is the more appropriate choice, and the performance comparison is beside the point.

Version tolerance is the second constraint. The README lists limited version-tolerant (fast/default) and full version-tolerant support as two separate modes. That phrasing implies the fast default is not fully version-tolerant, so a reader built against an older shape of a type may not handle a newer writer's output. The README does not document rollback behaviour or what happens on a mismatched read in either mode, so this is something to establish with your own tests before shipping a persisted format.

Unity deserves its own caution. The README states that Unity requirements and installation are completely different from the NuGet path and points to a separate section, with IL2CPP support via the .NET source generator. The generator is doing the work there too, so the Unity toolchain version is part of your compatibility surface, not just the package version.

How MemoryPack differs from protobuf-net and MessagePack for C#

The closest alternative is MessagePack for C#, by the same author. Both are binary, both support C#, and both have Unity support. The difference in approach is what the bytes contain. MessagePack follows the MessagePack specification, so its output is readable by MessagePack implementations in other languages; MemoryPack's format is its own, optimized for C# memory layout, which is why the README can claim the speed advantage. Choosing between them is choosing between interoperability and throughput.

protobuf-net is the other realistic comparison, and the README names it in the benchmark set. Its model is schema-first: you describe messages and generate types, and the wire format is the published Protocol Buffers format. That gives you cross-language readers and a versioning story that predates your project. MemoryPack inverts this by annotating the types you already have, which is less ceremony inside one C# solution and more friction the moment anything else needs to read the data.

FlatBuffers is the comparison the README itself draws for the zero-encoding idea, with the stated difference that MemoryPack does not require a special type. If your reason for considering FlatBuffers was zero-copy reads without a generated schema type, MemoryPack is aimed at exactly that case.

Maintenance, licensing, and what an upgrade costs

The repository is not archived, and the last push was on 2026-07-08. The most recent release listed is 1.21.4 from 2025-02-12, preceded by 1.21.3 on 2024-09-19 and 1.21.2 on 2024-09-18. So the release cadence is not fast, and the gap between the latest release and the latest push is worth noting if you depend on tagged versions rather than the main branch.

MemoryPack is MIT licensed. That permits commercial use and modification, and the repository includes a LICENSE file at the top level. This is not legal advice; check the licence text against your own distribution model, particularly if you ship modified source.

The upgrade cost is structural rather than financial. Because the wire format is generated from your type definitions, any change to which members are serialized is a format change. Adding a public property to a [MemoryPackable] class changes what the generator emits unless you mark it [MemoryPackIgnore]. Rolling out a new version therefore means coordinating writers and readers, and the limited version-tolerant mode is the tool the README offers for that. If your deployment cannot upgrade both sides together, plan for the full version-tolerant mode from the start rather than retrofitting it.

Editorial conclusion

Adopt MemoryPack when both ends of the wire are C# and you control the schema, especially for struct arrays where the README claims the largest gains over other binary serializers. Do not adopt it when a non-C# service must read the payload, when you need a published wire format, or when your serialized types change often and you cannot coordinate both sides. Before committing, verify three things: that your editor and SDK meet the Roslyn 4.3.1 requirement the README names, that every serialized type is marked partial, and that your versioning needs are covered by the limited version-tolerant mode or require the full one. The MIT licence removes most distribution concerns, but the format itself is the lock-in, not the licence.

Frequently asked questions

How do I install MemoryPack in a C# project?

It is distributed via NuGet, and the README gives the package-manager command Install-Package MemoryPack. The minimum requirement is .NET Standard 2.1, with .NET 7 recommended for best performance, and your editor needs Roslyn 4.3.1 support.

What does the MemoryPack example look like for a simple class?

You annotate a partial class with [MemoryPackable] and declare public properties, then call MemoryPackSerializer.Serialize and MemoryPackSerializer.Deserialize<Person>. The generator emits an IMemoryPackable<T> implementation, which you can inspect as a *.MemoryPackFormatter.g.cs file.

How does MemoryPack compare with protobuf?

The README benchmarks MemoryPack against protobuf-net and describes its format as C#-specific and zero-encoding, which is where the speed claims come from. protobuf-net uses the published Protocol Buffers format, so it can be read from other languages, which MemoryPack's format cannot.

Does MemoryPack work with Unity?

Yes, the README lists Unity support via the .NET source generator with IL2CPP, and states that Unity requirements and installation are completely different from the NuGet path, pointing to a separate section for the details.

Official sources

  1. Cysharp/MemoryPack on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cysharp-memorypack.svg)](https://hysenlabs.com/projects/cysharp-memorypack)