Skip to content
Created by

Generating code

A Protobuf schema is a simple file that describes a service, its methods (APIs), and their request/response types:

syntax = "proto3";
package connectrpc.eliza.v1;
message SayRequest {
string sentence = 1;
}
message SayResponse {
string sentence = 1;
}
service ElizaService {
rpc Say(SayRequest) returns (SayResponse) {}
}

A fully documented version of the above definition can be seen in the Buf Schema Registry (BSR).

The rpc keyword stands for Remote Procedure Call, an API method that can be invoked remotely. The schema is a contract between the server and client, and it precisely defines how data is exchanged.

Protobuf plugins are executables that accept .proto file inputs and generate various outputs (.kt files in this case). Performing generation on a remote machine makes local setup easier and allows the generation to take place in an isolated environment. We’ll use Buf, a modern replacement for Google’s protobuf compiler, along with remote plugins.

This requires the Buf CLI.

When developing a new project, two files need to be created:

The first file, buf.yaml, can be created by running:

Terminal window
$ buf config init

The second file, buf.gen.yaml, needs to be created manually and specifies which plugins should be used to generate code. An example of this file is shown below:

version: v2
managed:
enabled: true
plugins:
- remote: buf.build/protocolbuffers/java:v34.0
out: generated
opt: lite
- remote: buf.build/protocolbuffers/kotlin:v34.0
out: generated
opt: lite
- remote: buf.build/connectrpc/kotlin:v0.8.0
out: generated

Managed mode applies sensible Java defaults (one class per message, com. package prefix) so the .proto file stays free of language-specific options.

The three plugins emit:

  • The protocolbuffers/java plugin generates Java message classes for each Protobuf message and enum. opt: lite selects the lite runtime, which produces smaller binaries (useful on Android).
  • The protocolbuffers/kotlin plugin generates Kotlin DSL builders alongside the Java classes (e.g., sayRequest { sentence = "..." }). The matching opt: lite keeps it consistent with the Java output.
  • The Connect-Kotlin plugin generates the service-client interface and implementation from each service definition.

If you don’t need the Kotlin DSL builders, you can omit the protocolbuffers/kotlin plugin. If you need full Java reflection rather than lite, drop the opt: lite lines and switch your dependencies to protobuf-java / connect-kotlin-google-java-ext.

With these configuration files in place, generate code by running:

Terminal window
$ buf generate

Given the above config and example eliza.proto file, there should now be some generated files in the generated directory:

generated
└── com
└── connectrpc
└── eliza
└── v1
├── ElizaProto.java
├── ElizaProtoKt.proto.kt
├── ElizaServiceClient.kt
├── ElizaServiceClientInterface.kt
├── SayRequest.java
├── SayRequestKt.kt
├── SayRequestOrBuilder.java
├── SayResponse.java
├── SayResponseKt.kt
└── SayResponseOrBuilder.java

The *.java files come from protocolbuffers/java, the *Kt.kt files from protocolbuffers/kotlin, and ElizaServiceClient*.kt from connectrpc/kotlin.

Point out: at a directory on your Gradle source set (src/main/java for a single-module JVM project, or app/src/main/java for a typical Android project) so the generated files are picked up automatically.

The generated code depends on the Connect-Kotlin runtime and the Google Java Protobuf libraries. See Getting started → Set up Gradle for the matching Gradle dependencies, and Using clients → Using generated clients for how to call the generated client.

The following generation options can be combined in the opt field of the buf.gen.yaml file to customize outputs:

OptionTypeDefaultDetails
generateCallbackMethodsboolfalseGenerate callback signatures for unary methods.
generateCoroutineMethodsbooltrueGenerate suspend signatures for unary methods.
generateBlockingUnaryMethodsboolfalseGenerate blocking signatures for unary methods.