kotlinx.rpc 0.10.2 Help

Schema and codegen

The gRPC toolchain in kotlinx.rpc is schema-first. .proto files are the source of truth, built-in protoc plugins generate Kotlin declarations from them, and the kotlinx.rpc compiler plugin synthesizes the additional declarations required to make those generated files usable from Kotlin code and visible to runtime APIs such as withService, registerService, grpcMarshallerOf, and protoDescriptorOf.

Input schemas

Place schemas in the proto source set directories described on Configuration. A minimal schema can declare both messages and services:

syntax = "proto3"; package example.hello; message HelloRequest { string name = 1; } message HelloReply { string message = 1; } service Greeter { rpc SayHello(HelloRequest) returns (HelloReply); }

What protoc generates

The built-in protoc plugins are kotlin-multiplatform and grpc-kotlin-multiplatform. They generate source files into the module's build directory.

  • kotlin-multiplatform generates the public protobuf declarations. For a message file this means public message interfaces and enums in the declared package.

  • kotlin-multiplatform also generates a companion extension file named <FileName>.ext.kt and an internal support file in the _rpc_internal subdirectory.

  • grpc-kotlin-multiplatform generates public @Grpc service interfaces with unary and streaming signatures mapped to suspend and Flow.

A typical public output for the schema above looks like this:

package example.hello @GeneratedProtoMessage interface HelloRequest { val name: String } @GeneratedProtoMessage interface HelloReply { val message: String } @Grpc(protoPackage = "example.hello", protoServiceName = "Greeter") interface Greeter { suspend fun SayHello(message: HelloRequest): HelloReply }

The companion extension file contains the user-facing builder and copy helpers:

package example.hello operator fun HelloRequest.Companion.invoke( body: HelloRequest.Builder.() -> Unit ): HelloRequest fun HelloRequest.copy( body: HelloRequest.Builder.() -> Unit = {} ): HelloRequest

The internal protobuf support file contains the implementation details used by the runtime and should not be used directly.

What the compiler plugin adds

The compiler plugin completes the generated declarations rather than replacing them. Its responsibilities are distinct from the protoc plugins:

Companion and Builder synthesis

The public message interfaces generated by protoc are annotated with @GeneratedProtoMessage. The compiler plugin synthesizes the nested Companion object and Builder interface that make the generated .ext.kt builder helpers callable from Kotlin code.

Marshaller and descriptor binding

The compiler plugin associates each public generated message type with the corresponding internal MARSHALLER and DESCRIPTOR objects. That is what makes grpcMarshallerOf<Message>() and protoDescriptorOf<Message>() work on the public type.

Service metadata synthesis

For @Grpc services, the compiler plugin synthesizes hidden stub metadata used by withService, registerService, and serviceDescriptorOf.

Declaration validation

The compiler plugin validates generated and handwritten gRPC declarations during compilation.

In practice, the generated API is used like this:

val request = HelloRequest { name = "kotlinx.rpc" } val requestCopy = request.copy { name = "grpc" } val marshaller = grpcMarshallerOf<HelloRequest>(ProtoConfig(discardUnknownFields = true)) val descriptor = protoDescriptorOf<HelloRequest>() val service = grpcClient.withService<Greeter>()

Generated protobuf marshallers use ProtoConfig as their runtime configuration object. The current configuration options are discardUnknownFields, recursionLimit, and extensionRegistry.

Validation rules

The compiler plugin enforces the rules that are required by the current gRPC runtime and generator model.

  • A gRPC service function has exactly one parameter unless it is a zero-argument unary RPC.

  • Nullable request and response types are not allowed in @Grpc services.

  • Client streaming must be the top-level parameter type. Nested flows inside request objects are rejected.

  • Overridden proto package names, service names, and method names must be valid protobuf identifiers.

  • @Grpc.Method(safe = true) also requires idempotent = true.

  • @GeneratedProtoMessage declarations are generator output. Do not write them by hand.

Last modified: 10 March 2026