LightProto 0.7.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package LightProto --version 0.7.1
                    
NuGet\Install-Package LightProto -Version 0.7.1
                    
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="LightProto" Version="0.7.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LightProto" Version="0.7.1" />
                    
Directory.Packages.props
<PackageReference Include="LightProto" />
                    
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 LightProto --version 0.7.1
                    
#r "nuget: LightProto, 0.7.1"
                    
#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 LightProto@0.7.1
                    
#: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=LightProto&version=0.7.1
                    
Install as a Cake Addin
#tool nuget:?package=LightProto&version=0.7.1
                    
Install as a Cake Tool

LightProto

.NET NuGet downloads Build codecov CodeQL Advanced GitHub Repo stars Size License

A high‑performance, Native AOT–friendly Protocol Buffers implementation for C#/.NET.

Why LightProto?

protobuf-net is a popular Protocol Buffers implementation in .NET, but some scenarios (especially Native AOT) can be challenging due to runtime reflection and dynamic generation. LightProto addresses this with compile-time code generation and a protobuf-net–style API.

Features

  • Source generator–powered serializers/parsers at compile time
  • protobuf-net–style Serializer API and familiar attributes
  • Target frameworks: netstandard2.0, net8.0, net9.0, net10.0
  • Performance is about 20%-50% better than protobuf-net
  • AOT-friendly by design
  • Stream and IBufferWriter<byte> serialization or ToByteArray
  • ReadOnlySpan<byte>/ReadOnlySequence<byte>/Stream deserialization

Performance & Benchmarks

The following benchmarks compare serialization performance between LightProto, protobuf-net, and Google.Protobuf.

You can reproduce these by cloning the repo and running tests/Benchmark.

BenchmarkDotNet v0.15.3, Windows 11 (10.0.26100.4652/24H2/2024Update/HudsonValley)
AMD Ryzen 7 5800X 3.80GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 10.0.100-rc.1.25451.107
[Host]    : .NET 8.0.20 (8.0.20, 8.0.2025.41914), X64 RyuJIT x86-64-v3
.NET 10.0 : .NET 10.0.0 (10.0.0-rc.1.25451.107, 10.0.25.45207), X64 RyuJIT x86-64-v3
.NET 8.0  : .NET 8.0.20 (8.0.20, 8.0.2025.41914), X64 RyuJIT x86-64-v3
.NET 9.0  : .NET 9.0.9 (9.0.9, 9.0.925.41916), X64 RyuJIT x86-64-v3
Method Job Runtime Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
Serialize_ProtoBuf_net .NET 10.0 .NET 10.0 645.6 μs 12.70 μs 11.88 μs 1.39 0.03 526.41 KB 1.03
Serialize_GoogleProtoBuf .NET 10.0 .NET 10.0 539.9 μs 10.71 μs 12.75 μs 1.16 0.03 512.95 KB 1.00
Serialize_LightProto .NET 10.0 .NET 10.0 465.1 μs 7.88 μs 6.99 μs 1.00 0.02 512.95 KB 1.00
Serialize_ProtoBuf_net .NET 8.0 .NET 8.0 757.0 μs 12.80 μs 11.98 μs 1.42 0.04 526.41 KB 1.03
Serialize_GoogleProtoBuf .NET 8.0 .NET 8.0 553.9 μs 10.97 μs 9.72 μs 1.04 0.03 512.95 KB 1.00
Serialize_LightProto .NET 8.0 .NET 8.0 531.9 μs 10.52 μs 14.04 μs 1.00 0.04 512.95 KB 1.00
Serialize_ProtoBuf_net .NET 9.0 .NET 9.0 712.6 μs 13.61 μs 12.73 μs 1.39 0.04 526.41 KB 1.03
Serialize_GoogleProtoBuf .NET 9.0 .NET 9.0 546.7 μs 10.70 μs 16.33 μs 1.07 0.04 512.95 KB 1.00
Serialize_LightProto .NET 9.0 .NET 9.0 513.6 μs 10.15 μs 13.89 μs 1.00 0.04 512.95 KB 1.00
Method Job Runtime Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
Deserialize_ProtoBuf_net .NET 10.0 .NET 10.0 569.2 μs 10.88 μs 12.53 μs 1.38 0.04 562 KB 0.84
Deserialize_GoogleProtoBuf .NET 10.0 .NET 10.0 441.4 μs 8.67 μs 10.64 μs 1.07 0.04 648.7 KB 0.97
Deserialize_LightProto .NET 10.0 .NET 10.0 411.5 μs 8.08 μs 9.92 μs 1.00 0.03 665.95 KB 1.00
Deserialize_ProtoBuf_net .NET 8.0 .NET 8.0 688.0 μs 13.51 μs 15.56 μs 1.55 0.05 562 KB 0.84
Deserialize_GoogleProtoBuf .NET 8.0 .NET 8.0 595.5 μs 11.51 μs 16.14 μs 1.34 0.04 648.7 KB 0.97
Deserialize_LightProto .NET 8.0 .NET 8.0 444.8 μs 8.88 μs 9.12 μs 1.00 0.03 665.95 KB 1.00
Deserialize_ProtoBuf_net .NET 9.0 .NET 9.0 662.3 μs 12.60 μs 11.17 μs 1.53 0.04 562 KB 0.84
Deserialize_GoogleProtoBuf .NET 9.0 .NET 9.0 491.7 μs 9.64 μs 13.52 μs 1.14 0.04 648.7 KB 0.97
Deserialize_LightProto .NET 9.0 .NET 9.0 431.9 μs 8.33 μs 9.25 μs 1.00 0.03 665.95 KB 1.00

Note: Results vary by hardware, runtime, and data model. Please run the benchmarks on your environment for the most relevant numbers.

Quick Start

Install from NuGet:

dotnet add package LightProto

Define your contracts (partial classes) using LightProto attributes:

using LightProto;

[ProtoContract]
public partial class Person
{
    [ProtoMember(1)]
    public string Name { get; set; } = string.Empty;

    [ProtoMember(2)]
    public int Age { get; set; }
}

var person = new Person { Name = "Alice", Age = 30 };

// Serialize to a byte[]
byte[] bytes = person.ToByteArray();
// person.ToByteArray(Person.ProtoWriter); // use this overload when .netstandard2.0

// Or serialize to a Stream
using var stream = new MemoryStream();
Serializer.Serialize(stream, person);
// Serializer.Serialize(stream, person, Person.ProtoWriter); // use this overload when .netstandard2.0

byte[] data = stream.ToArray();

// Deserialize from byte[] (ReadOnlySpan<byte> overload will be used)
Person fromBytes = Serializer.Deserialize<Person>(bytes);
// Person fromBytes = Serializer.Deserialize<Person>(bytes,Person.ProtoReader); // use this overload when .netstandard2.0

// Or deserialize from Stream
using var input = new MemoryStream(data);
Person fromStream = Serializer.Deserialize<Person>(input);
// Person fromStream = Serializer.Deserialize<Person>(input,Person.ProtoReader); // use this overload when .netstandard2.0

Warnings

This project is under active development and may introduce breaking changes. Use in production at your own risk.

Migration from protobuf-net

Most code migrates by swapping the namespace and marking your types partial.

  1. Replace ProtoBuf with LightProto.
  2. Mark serializable types as partial.
  3. Remove runtime configuration (e.g., RuntimeTypeModel). LightProto generates code at compile time.

Example:

- using ProtoBuf;
+ using LightProto;

[ProtoContract]
- public class Person
+ public partial class Person
{
    [ProtoMember(1)]
    public string Name { get; set; } = string.Empty;

    [ProtoMember(2)]
    public int Age { get; set; }
}

var myObject = new Person { Name = "Alice", Age = 30 };

// Serialization
var stream = new MemoryStream();
Serializer.Serialize(stream, myObject);
byte[] data = stream.ToArray();

// Deserialization
var obj = Serializer.Deserialize<Person>(new ReadOnlySpan<byte>(data));

Common replacements:

  • RuntimeTypeModel and runtime surrogates → use compile-time attributes (see Surrogates below).
  • Non-partial types → mark as partial to enable generator output.

Need to know

LightProto aims to minimize differences from protobuf-net; notable ones include:

  • Partial classes required

    • protobuf-net: partial not required
    • LightProto: mark [ProtoContract] types as partial so the generator can emit code
  • Generic Serialize/Deserialize type constraint

    • protobuf-net: Serializer.Serialize<int>(...) and Serializer.Deserialize<int>(...)
    • LightProto: T must implement IProtoParser<T> (i.e., a generated message type); primitives are not supported directly. Use another method which pass IProtoReader/Writer explicitly.
      int a=10;
      ArrayBufferWriter<byte> writer = new ArrayBufferWriter<byte>();
      LightProto.Serializer.Serialize<int>(writer, a,Int32ProtoParser.Writer); // must pass writer
      var bytes = a.ToByteArray(Int32ProtoParser.Writer); // extension method
      int result = LightProto.Serializer.Deserialize<int>(bytes,Int32ProtoParser.Reader); // must pass reader
      
      List<int> list=[1,2,3];
      var bytes = list.ToByteArray(Int32ProtoParser.Writer);// extension method
      ArrayBufferWriter<byte> writer = new ArrayBufferWriter<byte>();
      LightProto.Serializer.Serialize(writer, list,Int32ProtoParser.Writer);// must pass element writer
      List<int> arr2=LightProto.Serializer.Deserialize<List<int>,int>(bytes,Int32ProtoParser.Reader); // must pass element reader
      
  • IExtensible

    • protobuf-net: supports IExtensible for dynamic extensions
    • LightProto: IExtensible is defined for compatibility only and has no effect
  • Surrogates

    • protobuf-net: can register surrogates via RuntimeTypeModel at runtime

    • LightProto: define at compile time via attributes

      Example for Guid:

      namespace LightProto.Parser; //must defined in this namespace
      [ProtoContract]
      [ProtoSurrogateFor<Guid>]
      public partial struct GuidProtoParser // name must be <OriginalTypeName>ProtoParser
      {
          [ProtoMember(1, DataFormat = DataFormat.FixedSize)]
          internal ulong Low { get; set; }
      
          [ProtoMember(2, DataFormat = DataFormat.FixedSize)]
          internal ulong High { get; set; }
      
          public static implicit operator Guid(GuidProtoParser protoParser) //must define implicit conversions
          {
              Span<byte> bytes = stackalloc byte[16];
              BinaryPrimitives.WriteUInt64LittleEndian(bytes, protoParser.Low);
              BinaryPrimitives.WriteUInt64LittleEndian(bytes.Slice(8), protoParser.High);
              return new Guid(bytes);
          }
      
          public static implicit operator GuidProtoParser(Guid value) //must define implicit conversions
          {
              Span<byte> bytes = stackalloc byte[16];
              value.TryWriteBytes(bytes);
              return new GuidProtoParser()
              {
                  Low = BinaryPrimitives.ReadUInt64LittleEndian(bytes),
                  High = BinaryPrimitives.ReadUInt64LittleEndian(bytes.Slice(8)),
              };
          }
      }
      
  • StringIntern

    • protobuf-net: Use RuntimeTypeModel.Default.StringInterning = true; to enable string interning globally
    • LightProto: [StringIntern] attribute can apply to individual string members/class/module/assembly
  • RuntimeTypeModel

    • Not supported; all configuration is static via attributes and generated code

If you encounter different behavior versus protobuf-net, please open an issue.

Working with .proto files

LightProto doesn’t ship a .proto → C# generator. You can generate C# using protobuf-net (or other tools), then adapt the output to LightProto (typically replacing the ProtoBuf namespace with LightProto and marking types partial). If something doesn’t work, please file an issue.

Contributing

Contributions are welcome!

  1. Check existing issues and discussions
  2. Follow the project’s coding standards
  3. Add tests for new functionality
  4. Update documentation as needed

Development setup:

git clone https://github.com/dameng324/LightProto.git
cd LightProto
dotnet restore
dotnet build
dotnet test

License

MIT License — see LICENSE for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on LightProto:

Package Downloads
JK.Mexc.Net

JK.Mexc.Net is a high performance client library for accessing the Mexc REST and Websocket API. All data is mapped to readable models and enum values. Additional features include automatic websocket (re)connection management, an implementation for maintaining a client side order book, easy integration with other exchange client libraries and more.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.1 117 1/26/2026
1.2.0 100 1/21/2026
1.1.1 96 1/12/2026
1.1.0 96 1/10/2026
1.0.1 101 1/6/2026
1.0.0 97 1/4/2026
0.9.5 178 12/24/2025
0.9.4 272 12/18/2025
0.9.3 271 12/18/2025
0.9.2 277 12/17/2025
0.9.1 273 12/16/2025
0.9.0 5,250 12/12/2025
0.8.5 387 11/17/2025
0.8.4 228 10/27/2025
0.8.3 113 10/25/2025
0.8.2 126 10/25/2025
0.8.1 192 10/23/2025
0.8.0 196 10/20/2025
0.7.1 208 10/15/2025
0.7.0 119 10/11/2025
Loading failed