FSharp.Grpc.Tools
0.1.3
dotnet add package FSharp.Grpc.Tools --version 0.1.3
NuGet\Install-Package FSharp.Grpc.Tools -Version 0.1.3
<PackageReference Include="FSharp.Grpc.Tools" Version="0.1.3" />
<PackageVersion Include="FSharp.Grpc.Tools" Version="0.1.3" />
<PackageReference Include="FSharp.Grpc.Tools" />
paket add FSharp.Grpc.Tools --version 0.1.3
#r "nuget: FSharp.Grpc.Tools, 0.1.3"
#:package FSharp.Grpc.Tools@0.1.3
#addin nuget:?package=FSharp.Grpc.Tools&version=0.1.3
#tool nuget:?package=FSharp.Grpc.Tools&version=0.1.3
FSharp.Grpc
F# code generation from .proto files. Generates F# records, enums, and discriminated unions with binary and JSON serialization. Generates gRPC server and client stubs.
Documentation
- Messages — setup, type mapping, JSON, examples
- gRPC Server — setup, handler signatures, all streaming patterns, testing
- gRPC Client — setup, client creation, all streaming patterns
Overview
syntax = "proto3";
package example;
message Person {
string name = 1;
int32 age = 2;
}
open Example
let alice = { Person.empty with Name = "Alice"; Age = 30 }
let bytes = Person.encode alice
let decoded = Person.decode bytes
let json = Person.encodeJson alice
// {"name":"Alice","age":30}
Getting started
dotnet new console -lang F# -n MyApp
cd MyApp
dotnet add package FSharp.Grpc.Tools.Codegen
Add a proto file and register it in your .fsproj:
<ItemGroup>
<Protobuf Include="protos/person.proto"/>
</ItemGroup>
Build and use the generated types:
dotnet build
open Example
let request = { Person.empty with Name = "World"; Age = 30 }
let bytes = Person.encode request
let json = Person.encodeJson request
Features
| Proto feature | F# representation |
|---|---|
| Scalar fields | Record fields |
message fields |
TypeName option |
optional scalars |
scalar option |
repeated fields |
type list |
map<K, V> fields |
Map<K, V> |
enum |
F# enum + companion module |
oneof |
Discriminated union |
| Well-known types | Google.Protobuf.WellKnownTypes |
| Wrapper types | Unwrapped option |
| Binary serialization | encode / decode |
| JSON serialization | encodeJson / decodeJson |
| gRPC services | Server + client stubs |
gRPC services
Set GrpcServices metadata to generate server and client stubs:
<Protobuf Include="protos/greeter.proto" GrpcServices="Both"/>
Server
open Greeter
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.DependencyInjection
let handlers: GreeterHandlers =
{ SayHello =
fun req ctx ->
task { return { HelloReply.empty with Message = $"Hello {req.Name}!" } } }
let builder = WebApplication.CreateBuilder()
builder.Services.AddGrpc() |> ignore
builder.Services.AddSingleton(GreeterService(handlers)) |> ignore
let app = builder.Build()
app.MapGrpcService<GreeterService>() |> ignore
app.Run()
Client
open Greeter
let run () = task {
let client = GreeterClient.create "https://localhost:5001"
let! reply = client.SayHello { HelloRequest.empty with Name = "World" }
printfn "%s" reply.Message
}
Supported patterns: unary, server streaming, client streaming, bidirectional streaming.
GrpcServices value |
Messages | Server stubs | Client stubs |
|---|---|---|---|
None (default) |
Yes | No | No |
Server |
Yes | Yes | No |
Client |
Yes | No | Yes |
Both |
Yes | Yes | Yes |
Wire compatibility
Generated code produces the same wire format as C#, Go, Java, Python, and other protobuf implementations. Tested with 50 cross-language serialization tests and 10 cross-language gRPC tests (F# server + C# client, C# server + F# client).
Benchmarks
Apple M3 Max, .NET 10.0:
Binary
Person (2 fields):
| Method | Mean | Allocated |
|---|---|---|
| C# Encode | 23.12 ns | 112 B |
| F# Encode | 23.45 ns | 112 B |
| C# Decode | 40.01 ns | 256 B |
| F# Decode | 28.97 ns | 248 B |
ScalarTypes (15 fields):
| Method | Mean | Allocated |
|---|---|---|
| C# Encode | 117.4 ns | 200 B |
| F# Encode | 171.3 ns | 264 B |
| C# Decode | 128.1 ns | 424 B |
| F# Decode | 138.7 ns | 448 B |
UserProfile (enum, nested message, repeated, maps, oneof):
| Method | Mean | Allocated |
|---|---|---|
| C# Encode | 453.6 ns | 496 B |
| F# Encode | 442.6 ns | 504 B |
| C# Decode | 622.5 ns | 2,640 B |
| F# Decode | 829.0 ns | 5,200 B |
JSON
Person (2 fields):
| Method | Mean | Allocated |
|---|---|---|
| C# JSON Encode | 130.54 ns | 568 B |
| F# JSON Encode | 99.97 ns | 944 B |
| C# JSON Decode | 207.10 ns | 560 B |
| F# JSON Decode | 186.04 ns | 216 B |
ScalarTypes (15 fields):
| Method | Mean | Allocated |
|---|---|---|
| C# JSON Encode | 1,241.1 ns | 3.2 KB |
| F# JSON Encode | 677.5 ns | 6.91 KB |
| C# JSON Decode | 1,953.7 ns | 3.45 KB |
| F# JSON Decode | 1,124.1 ns | 1.27 KB |
UserProfile (enum, nested message, repeated, maps, oneof):
| Method | Mean | Allocated |
|---|---|---|
| C# JSON Encode | 1,670.5 ns | 4.56 KB |
| F# JSON Encode | 965.6 ns | 7.69 KB |
| C# JSON Decode | 2,791.8 ns | 6.42 KB |
| F# JSON Decode | 2,185.8 ns | 4.28 KB |
Requirements
- .NET 8.0 SDK or later
protocis resolved automatically from theGrpc.ToolsNuGet package
Limitations
- Proto3 only. Proto2 syntax is not supported.
- The deprecated
groupfield type is rejected.
License
MIT. See LICENSE.
Developed with Claude Code.
| Product | Versions 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 was computed. 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 was computed. 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 was computed. 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 | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Fabulous.AST (>= 1.10.0)
- FSharp.Core (>= 11.0.100)
- Google.Protobuf (>= 3.34.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.