Skip to content

Kotlin

Bufrnix provides comprehensive Kotlin code generation support for Protocol Buffers, including gRPC services with coroutines and Connect RPC, leveraging Kotlin’s modern language features.

{
languages.kotlin = {
enable = true;
jvmTarget = 17;
kotlinVersion = "2.1.20";
};
}
  • ✅ Protocol Buffers 3 support (built into protoc)
  • ✅ Kotlin DSL builders for messages
  • ✅ Immutable message updates with copy
  • ✅ gRPC with coroutines support
  • ✅ Connect RPC support
  • ✅ Flow-based streaming APIs
  • ✅ Gradle build file generation
  • ✅ Null safety and type safety

Kotlin support requires both Java and Kotlin outputs to be generated, as Kotlin protobuf support extends Java classes. This is handled automatically by Bufrnix.

OptionTypeDefaultDescription
enableboolfalseEnable Kotlin code generation
jdkpackagepkgs.jdk17JDK to use for plugins
outputPathstring"gen/kotlin"Base output directory
javaOutputPathstring"gen/kotlin/java"Java output directory
kotlinOutputPathstring"gen/kotlin/kotlin"Kotlin output directory
kotlinVersionstring"2.1.20"Kotlin version
protobufVersionstring"4.28.2"Protobuf version
jvmTargetint17JVM target version
coroutinesVersionstring"1.8.0"Kotlinx coroutines version
generateBuildFilebooltrueGenerate build.gradle.kts
projectNamestring"GeneratedProtos"Gradle project name

Enable coroutine-based gRPC code generation:

{
languages.kotlin = {
enable = true;
grpc = {
enable = true;
grpcKotlinVersion = "1.4.2";
};
};
}
OptionTypeDefaultDescription
grpc.enableboolfalseEnable gRPC generation
grpc.grpcVersionstring"1.62.2"gRPC Java version
grpc.grpcKotlinVersionstring"1.4.2"gRPC Kotlin version
grpc.grpcKotlinJarpathnullPath to plugin JAR
grpc.generateServiceImplboolfalseGenerate service stubs

Enable modern HTTP-based RPC with Connect:

{
languages.kotlin = {
enable = true;
connect = {
enable = true;
connectVersion = "0.7.3";
generateClientConfig = true;
};
};
}
OptionTypeDefaultDescription
connect.enableboolfalseEnable Connect RPC
connect.connectVersionstring"0.7.3"Connect version
connect.connectKotlinJarpathnullPath to plugin JAR
connect.packageNamestring"com.example.connect"Package for config
connect.generateClientConfigboolfalseGenerate client helper
flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
bufrnix.url = "github:bufrnix/bufrnix";
};
outputs = { self, nixpkgs, bufrnix }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system}.default = bufrnix.lib.mkBufrnixPackage {
inherit (pkgs) lib;
inherit pkgs;
config = {
root = ./proto;
languages.kotlin = {
enable = true;
generateBuildFile = true;
projectName = "MyKotlinProtos";
};
};
};
};
}
{
languages.kotlin = {
enable = true;
grpc = {
enable = true;
# JAR will be downloaded automatically
# grpcKotlinJar = ./path/to/protoc-gen-grpc-kotlin.jar; # Optional manual path
};
};
}
{
languages.kotlin = {
enable = true;
jvmTarget = 21;
kotlinVersion = "2.1.20";
protobufVersion = "4.28.2";
coroutinesVersion = "1.8.0";
# Custom output paths
javaOutputPath = "gen/java";
kotlinOutputPath = "gen/kotlin";
# Build configuration
generateBuildFile = true;
projectName = "MyProtos";
generatePackageInfo = true;
# gRPC with coroutines
grpc = {
enable = true;
grpcVersion = "1.62.2";
grpcKotlinVersion = "1.4.2";
generateServiceImpl = true;
};
# Connect RPC
connect = {
enable = true;
connectVersion = "0.7.3";
packageName = "com.mycompany.connect";
generateClientConfig = true;
};
};
}

The Kotlin module generates:

gen/kotlin/
├── java/ # Java protobuf classes
│ └── com/example/
│ └── MyMessage.java
├── kotlin/ # Kotlin extensions
│ └── com/example/
│ ├── MyMessageKt.kt # DSL builders
│ └── MyServiceGrpcKt.kt # Coroutine stubs
├── build.gradle.kts # Gradle build file
└── settings.gradle.kts # Gradle settings

After building the package, run the generated script to create the protobuf files:

Terminal window
# Build the package
nix build
# Generate the protobuf code
./result/bin/bufrnix

This will create the generated Kotlin files in the gen/kotlin/ directory according to your configuration.

On macOS ARM64 systems, Bufrnix automatically handles the gRPC Java plugin compatibility by using Rosetta 2 for x86_64 binaries. This ensures compatibility across all Apple Silicon machines.

import com.example.protos.*
// Create messages with DSL
val user = user {
id = "123"
name = "John Doe"
emails += "john@example.com"
profile = userProfile {
bio = "Kotlin developer"
}
}
// Immutable updates
val updated = user.copy {
name = "Jane Doe"
}
// Server implementation
class MyService : MyServiceGrpcKt.MyServiceCoroutineImplBase() {
override suspend fun getUser(request: GetUserRequest): User {
// Suspend function for async operations
val user = userRepository.findById(request.id)
return user {
id = user.id
name = user.name
}
}
override fun listUsers(request: ListRequest): Flow<User> = flow {
// Flow-based streaming
userRepository.findAll().forEach { user ->
emit(user)
delay(100)
}
}
}
// Client usage
val stub = MyServiceGrpcKt.MyServiceCoroutineStub(channel)
val user = stub.getUser(getUserRequest { id = "123" })
import com.connectrpc.ConnectInterceptor
import com.connectrpc.ProtocolClientConfig
import com.connectrpc.okhttp.ConnectOkHttpClient
// Using generated client config
val client = ConnectConfig.createClient(
host = "https://api.example.com",
interceptors = listOf(authInterceptor)
)
// Make RPC calls
val response = client.unary(
path = "/example.v1.MyService/GetUser",
request = getUserRequest { id = "123" }
)

The gRPC and Connect Kotlin plugins are distributed as JAR files. Bufrnix can either:

  1. Use provided JARs: Set grpcKotlinJar or connectKotlinJar paths
  2. Download automatically: Leave paths null (downloads to .bufrnix-cache/)

Example with manual JAR:

{
grpc.grpcKotlinJar = pkgs.fetchurl {
url = "https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-kotlin/1.4.2/protoc-gen-grpc-kotlin-1.4.2-jdk8.jar";
sha256 = "...";
};
}
  1. Java compatibility: Always ensure Java and Kotlin outputs use compatible package names
  2. Coroutines: Use kotlinx-coroutines-core for async operations
  3. Build tools: Generated Gradle files work with Gradle 8.10.2+
  4. Version alignment: Keep protobuf, gRPC, and Kotlin versions aligned
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    bufrnix = {
      url = "github:conneroisu/bufrnix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = {
    nixpkgs,
    flake-utils,
    bufrnix,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (
      system: let
        pkgs = nixpkgs.legacyPackages.${system};

        # Generate protobuf code
        protoGen = bufrnix.lib.mkBufrnixPackage {
          inherit pkgs;

          config = {
            root = ./proto;
            languages = {
              kotlin = {
                enable = true;
                generateBuildFile = true;
                projectName = "KotlinProtoExample";
              };
            };
          };
        };
      in {
        packages = {
          default = protoGen;
          proto = protoGen;
        };

        devShells.default = pkgs.mkShell {
          buildInputs = with pkgs; [
            jdk17
            kotlin
            gradle
            protobuf
          ];

          shellHook = ''
            echo "Kotlin Proto Example Development Shell"
            echo "Run 'nix build .#proto' to generate proto code"
            echo "Run 'gradle build' to build the Kotlin project"
            echo "Run 'gradle run' to execute the example"
          '';
        };
      }
    );
}