Skip to content
Projects

JasonXuDeveloper/Nino has 660 GitHub stars and 59 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 14:02 UTC. Last push 2026-11-15.

How these counts are measured

Measured star growth

in 24h
0
in 7 days
Collecting history
in 15 days
Collecting history
in 1 month
Collecting history

Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.

About

The fastest binary serializer for C#. Source-generated, zero-allocation, thread-safe and safe on untrusted input: .NET, Native AOT, Unity, Godot and HybridCLR, with Go, Rust and TypeScript writing and reading the same bytes.

Developer Tools

README.md

Original
Nino logo

Nino

The fastest binary serializer for C#.
Source-generated, zero-allocation, thread-safe and safe on untrusted input.
For .NET, Unity (Mono and IL2CPP), Godot, Native AOT and HybridCLR, with Go, Rust and TypeScript writing and reading the identical bytes.

NuGet OpenUPM crates.io
npm Go
Build License Docs DeepWiki

Website · Getting started · What's new in v4 · Benchmarks · 中文

Why Nino

  • Fastest. On 12 real-world workloads it serializes 1.5–5.4× faster than MemoryPack, 3.4–18× than MessagePack, 6.4–73× than protobuf-net, 3.9–34× than Google.Protobuf and 4.3–136× than System.Text.Json. Benchmarks
  • SIMD everywhere, Burst in Unity. Hand-written vector paths for AVX-512, AVX2, SSSE3, Arm64 and WebAssembly move tuples, padded structs and strings; Burst kernels in Unity, vector kernels in Go, Rust and TypeScript, and a portable fallback that writes the same bytes. SIMD
  • Safe on untrusted input. Crafted bytes cannot crash the process, read past the input, allocate out of proportion or name a type to create; every invalid input throws one NinoDataException. Untrusted data
  • Zero allocation on hot paths. Serialize into a reused IBufferWriter<byte>, deserialize into existing or pooled objects; thread-safe, no locks on the hot path. Zero allocation
  • Everything at compile time. Generated formatters read and write your members directly: no reflection over them, no IL emit, no registration; runs on IL2CPP, Native AOT and HybridCLR hot updates. Platforms
  • The same bytes everywhere. Every runtime and CPU writes identical bytes, and so do Go, Rust and TypeScript, which read and write your types through the code nino-gen generates. Other languages
  • Rich types that evolve. Polymorphism without tags, version-tolerant and keyed types, reference tracking, serialization callbacks, every BCL collection. Supported types
  • Mistakes caught as you type. 44 analyzer diagnostics, many with a one-click fix, and a layout baseline that flags any change to a saved or sent type that old data or old builds could not read. Analyzers

Install

Command
.NET, Godot 4 dotnet add package Nino --prerelease .NET 8 and later (builds tuned for .NET 8 and .NET 10), .NET Standard 2.1, Native AOT; add-ons Nino.Immutable, Nino.AspNetCore, Nino.Codegen
Unity 2022.3+ openupm add com.jasonxudeveloper.nino Mono, IL2CPP, HybridCLR · guide
Go 1.22+ go get github.com/JasonXuDeveloper/Nino/runtimes/go/v4 generated code or struct tags · guide
Rust 1.88+ cargo add nino-serialization generated code or --features derive · guide
TypeScript npm install nino-serialization Node.js and browsers · guide

v4 is a prerelease: without --prerelease NuGet installs 3.9.x, which cannot read v4 data. Nino.Codegen writes your types as Go, Rust or TypeScript after each build (guide).

Quick start

using Nino.Core;

[NinoType]
public sealed class Order
{
    public long Id;
    public string Customer;
    public List<OrderLine> Lines;
}

byte[] bytes = NinoSerializer.Serialize(order);
Order copy = NinoDeserializer.Deserialize<Order>(bytes);
NinoDeserializer.Deserialize(bytes, ref copy); // fills the same instance in place

Polymorphism needs no tags: a value declared as its base is read back as its runtime type.

[NinoType] public abstract class Message { public int Seq; }
[NinoType] public sealed class Chat : Message { public string Text; }

byte[] bytes = NinoSerializer.Serialize<Message>(new Chat { Text = "hi" });
Message msg = NinoDeserializer.Deserialize<Message>(bytes); // a Chat again

Next: your first types, evolving data, reference tracking, pooling and the advanced guides.

AI coding assistants

npx skills add JasonXuDeveloper/Nino

The nino-serialization skill teaches Claude Code, Codex, Cursor, Copilot and other agents to declare [NinoType]s, pick the right format and fix every NINO diagnostic. The docs are also in llms.txt and llms-full.txt.

Benchmarks

12 real-world workloads Serialize Deserialize
vs MemoryPack 1.5–5.4× faster 1.3–3.5× faster
vs MessagePack 3.4–18× faster 2.2–12× faster
vs protobuf-net 6.4–73× faster 3.8–35× faster
vs Google.Protobuf 3.9–34× faster 2.3–32× faster
vs System.Text.Json 4.3–136× faster 3.7–91× faster
Into existing objects — 0 B, up to 7.6× faster than MemoryPack

The workloads: jvm-serializers' MediaContent and a Stack Exchange API page (the models of MessagePack's and MemoryPack's benchmarks); an RPC call whose result is an interface, a cached profile written by the previous version, an event store page of two-level event hierarchies in generic envelopes, and a log batch; and what games send: a state-sync snapshot read into the client's copy, lockstep input frames, an MMO AOI update, an SLG map region and a card battle replay that share objects, and an idle game's save from the previous version. Each library uses its fastest API (Google.Protobuf its own generated messages, System.Text.Json source-generated UTF-8) and, where it lacks a feature, its usual workaround (copies for shared objects, a new instance instead of reading into one). A range covers the workloads Nino wins by more than 5%; every time is in the docs.

Real workloads Real workloads: time per operation of Nino v4, v3 and every library, serialize and deserialize
Basic types and structs Basic types and structs: time per operation of Nino v4, v3 and every library, serialize and deserialize
Polymorphism Polymorphism: time per operation of Nino v4, v3 and every library, serialize and deserialize
Nullable values Nullable values: time per operation of Nino v4, v3 and every library, serialize and deserialize
Collections and common types Collections and common types: time per operation of Nino v4, v3 and every library, serialize and deserialize
Reuse and pooling Reuse and pooling: time per operation of Nino v4, v3 and every library, serialize and deserialize
Reference tracking and version tolerance Reference tracking and version tolerance: time per operation of Nino v4, v3 and every library, serialize and deserialize
Others Others: time per operation of Nino v4, v3 and every library, serialize and deserialize

BenchmarkDotNet 0.15.8, .NET 10.0.15, server GC, AMD EPYC 9V74 3.69 GHz, on GitHub's runners; all libraries in one run, Nino 3.3.13 from NuGet directly before it on the same machine. The Stack Exchange page takes 123,333 bytes in Nino, 134,223 in MemoryPack, 115,778 in MessagePack, 118,660 in protobuf (both libraries) and 208,038 in JSON. Method and every case: docs/v4-benchmarks.md.

More: every .NET case and Arm64, Unity with Burst and Go, Rust and TypeScript.

Built for

  • Services & IPC: no per-call allocations, safe concurrent use; ASP.NET Core bodies as application/x-nino.
  • RPC & networking: straight into a PipeWriter and out of a PipeReader's ReadOnlySequence<byte>, pooled messages, and a crafted message throws instead of taking the server down.
  • Message queues, caching and storage: polymorphic events, small payloads, fields added, reordered and removed across releases.
  • Web, Node, Go & Rust: types and codecs generated after each build, writing and reading the same bytes as .NET.
  • Unity: Mono and IL2CPP, HybridCLR without an init call, Burst SIMD kernels, AnimationCurve and Gradient built in.
  • Godot 4 (.NET): a regular NuGet package; Vector3, Transform3D and other math structs copied as raw memory.

Compared with other serializers

Nino v4 MemoryPack MessagePack protobuf System.Text.Json
Format binary, no per-value tags binary, memory layout MessagePack, self-describing Protocol Buffers, field numbers JSON text
Untrusted input safe by default, one exception type "trusted data only" opt-in UntrustedData depth limit depth limit
Polymorphism automatic, any base or interface [MemoryPackUnion] tags [Union] keys [ProtoInclude] numbers, oneof [JsonDerivedType] per subtype
Shared and circular references trackReferences circular references no no ReferenceHandler.Preserve
Read into existing objects in place, 0 B clears collections, new elements no merges, no overwrite members only (Populate)
Other languages Go, Rust, TypeScript, generated from your C# TypeScript any MessagePack library every protobuf library every language

protobuf covers protobuf-net and Google.Protobuf. Which to choose, and Nino's limitations: Choosing a Serializer. In depth: vs MemoryPack, vs MessagePack, vs protobuf-net.

v4 vs v3

v4 rewrote the runtime and the generator; its binary format is not compatible with v3.

v4 vs v3 (3.3.13)
Serialize 1.9× faster (class), 2.4× faster (class array), on par (struct), 1.2× faster (struct array)
Deserialize 1.5× faster (class), 1.5× faster (class array), on par (struct), on par (struct array)
Build generated code compiles 188× faster at 1,100 types (193 s → 1.03 s); 12× smaller source

What's new in v4 · Changelog · Migration guide

Contributing

Issues and pull requests are welcome; see CONTRIBUTING.md. Report security issues privately as SECURITY.md describes.

License

MIT © JasonXuDeveloper